plazercli 1.0.0 → 2.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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/args.ts","../src/cli/prompts.ts","../src/helpers/logger.ts","../src/generators/project.ts","../src/generators/base.ts","../src/helpers/filesystem.ts","../src/helpers/template.ts","../src/helpers/runtime.ts","../src/generators/frontend.ts","../src/installers/dependencyVersionMap.ts","../src/generators/backend.ts","../src/generators/docker.ts","../src/generators/env.ts","../src/generators/readme.ts","../src/generators/wiring.ts","../src/generators/liz.ts","../src/installers/database/prisma.ts","../src/installers/database/mongoose.ts","../src/installers/auth/jwt.ts","../src/installers/auth/magicLink.ts","../src/installers/auth/googleOauth.ts","../src/installers/queue/bullmq.ts","../src/installers/queue/rabbitmq.ts","../src/installers/infra/redis.ts","../src/installers/infra/smtp.ts","../src/installers/infra/minio.ts","../src/installers/infra/pm2.ts","../src/installers/multiTenant.ts","../src/installers/integrations/viacep.ts","../src/installers/integrations/whatsapp.ts","../src/installers/integrations/stripe.ts","../src/installers/integrations/mercadoPago.ts","../src/installers/integrations/abacatePay.ts","../src/installers/index.ts","../src/helpers/spinner.ts","../src/helpers/git.ts","../src/helpers/packages.ts","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport path from 'path';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n// Works from both src/cli/ (dev) and dist/ (built)\nconst pkgPath = path.resolve(__dirname, '../package.json');\nconst pkgPathAlt = path.resolve(__dirname, '../../package.json');\nconst pkg = JSON.parse(\n (() => {\n try { return readFileSync(pkgPath, 'utf-8'); }\n catch { return readFileSync(pkgPathAlt, 'utf-8'); }\n })()\n);\n\nexport interface CliFlags {\n name?: string;\n yes?: boolean;\n}\n\nexport function parseArgs(): CliFlags {\n const program = new Command();\n\n program\n .name('plazercli')\n .description('CLI para gerar projetos fullstack boilerplate')\n .version(pkg.version, '-v, --version')\n .option('-n, --name <name>', 'Nome do projeto')\n .option('-y, --yes', 'Usar valores padrão (skip prompts)')\n .parse();\n\n const opts = program.opts();\n return {\n name: opts.name,\n yes: opts.yes,\n };\n}\n","import { input, select, confirm, checkbox } from '@inquirer/prompts';\nimport type { ProjectConfig } from '../types/config.js';\nimport type { CliFlags } from './args.js';\nimport path from 'path';\n\nexport async function runPrompts(flags: CliFlags): Promise<ProjectConfig> {\n // 1. Nome do projeto\n const projectName = flags.name ?? await input({\n message: '📦 Qual o nome do projeto?',\n validate: (value) => {\n if (!value.trim()) return 'O nome do projeto é obrigatório';\n if (!/^[a-z0-9-]+$/.test(value)) return 'Use apenas letras minúsculas, números e hífens';\n return true;\n },\n });\n\n // 2. Descrição\n const projectDescription = await input({\n message: '📝 Descreva brevemente o projeto:',\n default: `Projeto ${projectName}`,\n });\n\n // 3. Runtime / Package Manager\n const runtime = await select({\n message: '⚡ Qual runtime/gerenciador de pacotes usar?',\n choices: [\n { name: 'pnpm (Recomendado)', value: 'pnpm' as const },\n { name: 'bun', value: 'bun' as const },\n { name: 'npm', value: 'npm' as const },\n ],\n });\n\n // 4. Banco de dados\n const database = await select({\n message: '🗄️ Qual banco de dados usar?',\n choices: [\n { name: 'PostgreSQL', value: 'postgresql' as const },\n { name: 'MySQL', value: 'mysql' as const },\n { name: 'MongoDB', value: 'mongodb' as const },\n { name: 'Nenhum', value: 'none' as const },\n ],\n });\n\n // 5. Multi-tenant\n const multiTenant = await confirm({\n message: '🏢 Usar multi-tenant?',\n default: false,\n });\n\n // 6. SMTP\n let smtp = await confirm({\n message: '📧 Configurar servidor SMTP (envio de emails)?',\n default: false,\n });\n\n // 7. Autenticação\n const authChoices = await checkbox({\n message: '🔐 Quais métodos de autenticação usar?',\n choices: [\n { name: 'JWT (JSON Web Token)', value: 'jwt' },\n { name: 'Magic Link (login por email)', value: 'magicLink' },\n { name: 'Google OAuth', value: 'googleOAuth' },\n ],\n });\n\n const auth = {\n jwt: authChoices.includes('jwt'),\n magicLink: authChoices.includes('magicLink'),\n googleOAuth: authChoices.includes('googleOAuth'),\n };\n\n // Auto-habilitar SMTP se Magic Link selecionado\n if (auth.magicLink && !smtp) {\n smtp = true;\n console.log(' ℹ SMTP habilitado automaticamente (necessário para Magic Link)');\n }\n\n // 8. Redis\n let redis = await confirm({\n message: '🔴 Usar Redis (cache/sessões)?',\n default: false,\n });\n\n // 9. Filas e Jobs\n const queue = await select({\n message: '📬 Usar filas e jobs?',\n choices: [\n { name: 'BullMQ (requer Redis)', value: 'bullmq' as const },\n { name: 'RabbitMQ', value: 'rabbitmq' as const },\n { name: 'Nenhum', value: 'none' as const },\n ],\n });\n\n // Auto-habilitar Redis se BullMQ\n if (queue === 'bullmq' && !redis) {\n redis = true;\n console.log(' ℹ Redis habilitado automaticamente (necessário para BullMQ)');\n }\n\n // 10. Frontend\n const frontend = await select({\n message: '🎨 Qual framework de frontend?',\n choices: [\n { name: 'Next.js', value: 'nextjs' as const },\n { name: 'React (Vite)', value: 'react-vite' as const },\n { name: 'Vue', value: 'vue' as const },\n { name: 'Angular', value: 'angular' as const },\n ],\n });\n\n // 11. Backend\n const backend = await select({\n message: '🔧 Qual framework de backend?',\n choices: [\n { name: 'Express', value: 'express' as const },\n { name: 'Fastify', value: 'fastify' as const },\n { name: 'NestJS', value: 'nestjs' as const },\n ],\n });\n\n // 12. Integrações\n const integrationChoices = await checkbox({\n message: '🔌 Quais integrações usar?',\n choices: [\n { name: 'ViaCEP (consulta CEP)', value: 'viacep' },\n { name: 'WhatsApp', value: 'whatsapp' },\n { name: 'Stripe (pagamentos)', value: 'stripe' },\n { name: 'Mercado Pago (pagamentos)', value: 'mercadoPago' },\n { name: 'AbacatePay (pagamentos)', value: 'abacatePay' },\n ],\n });\n\n const integrations = {\n viacep: integrationChoices.includes('viacep'),\n whatsapp: integrationChoices.includes('whatsapp'),\n stripe: integrationChoices.includes('stripe'),\n mercadoPago: integrationChoices.includes('mercadoPago'),\n abacatePay: integrationChoices.includes('abacatePay'),\n };\n\n // 13. MinIO\n const minio = await confirm({\n message: '📦 Usar MinIO para storage (S3-compatible)?',\n default: false,\n });\n\n // 14. PM2\n const pm2 = await confirm({\n message: '🔄 Usar PM2 para atualizações sem downtime?',\n default: false,\n });\n\n // Computed fields\n const projectDir = path.resolve(process.cwd(), projectName);\n const usePrisma = database === 'postgresql' || database === 'mysql';\n const useMongoose = database === 'mongodb';\n const hasAnyAuth = auth.jwt || auth.magicLink || auth.googleOAuth;\n const hasAnyIntegration = Object.values(integrations).some(Boolean);\n const hasAnyQueue = queue !== 'none';\n\n return {\n projectName,\n projectDescription,\n runtime,\n database,\n multiTenant,\n smtp,\n redis,\n minio,\n pm2,\n auth,\n queue,\n frontend,\n backend,\n integrations,\n projectDir,\n usePrisma,\n useMongoose,\n hasAnyAuth,\n hasAnyIntegration,\n hasAnyQueue,\n };\n}\n","import chalk from 'chalk';\n\nexport const logger = {\n info: (msg: string) => console.log(chalk.cyan(' ℹ'), msg),\n success: (msg: string) => console.log(chalk.green(' ✔'), msg),\n warn: (msg: string) => console.log(chalk.yellow(' ⚠'), msg),\n error: (msg: string) => console.log(chalk.red(' ✖'), msg),\n step: (msg: string) => console.log(chalk.blue(' →'), msg),\n title: (msg: string) => console.log(chalk.bold.white(`\\n ${msg}\\n`)),\n blank: () => console.log(),\n};\n\nexport function printBanner() {\n console.log(\n chalk.bold.cyan(`\n ╔═══════════════════════════════════════════════╗\n ║ ║\n ║ 🚀 PlazerCLI v1.0 ║\n ║ Fullstack Boilerplate Generator ║\n ║ ║\n ║ Oi! Eu sou a Liz, sua assistente. ║\n ║ Vou configurar seu projeto inteiro. ║\n ║ ║\n ╚═══════════════════════════════════════════════╝\n`)\n );\n}\n\nexport function printSummary(config: {\n projectName: string;\n frontend: string;\n backend: string;\n database: string;\n auth: { jwt: boolean; magicLink: boolean; googleOAuth: boolean };\n queue: string;\n redis: boolean;\n smtp: boolean;\n minio: boolean;\n pm2: boolean;\n multiTenant: boolean;\n integrations: Record<string, boolean>;\n}) {\n const authMethods = [\n config.auth.jwt && 'JWT',\n config.auth.magicLink && 'Magic Link',\n config.auth.googleOAuth && 'Google OAuth',\n ].filter(Boolean);\n\n const integrations = Object.entries(config.integrations)\n .filter(([, v]) => v)\n .map(([k]) => k);\n\n const infra = [\n config.redis && 'Redis',\n config.smtp && 'SMTP',\n config.minio && 'MinIO',\n config.pm2 && 'PM2',\n config.multiTenant && 'Multi-tenant',\n ].filter(Boolean);\n\n console.log(chalk.bold.white('\\n 📋 Liz preparou o resumo do projeto:\\n'));\n console.log(chalk.white(` Projeto: ${chalk.cyan(config.projectName)}`));\n console.log(chalk.white(` Frontend: ${chalk.cyan(config.frontend)}`));\n console.log(chalk.white(` Backend: ${chalk.cyan(config.backend)}`));\n console.log(chalk.white(` Banco de dados: ${chalk.cyan(config.database)}`));\n if (authMethods.length > 0) {\n console.log(chalk.white(` Autenticação: ${chalk.cyan(authMethods.join(', '))}`));\n }\n if (config.queue !== 'none') {\n console.log(chalk.white(` Filas: ${chalk.cyan(config.queue)}`));\n }\n if (infra.length > 0) {\n console.log(chalk.white(` Infra: ${chalk.cyan(infra.join(', '))}`));\n }\n if (integrations.length > 0) {\n console.log(chalk.white(` Integrações: ${chalk.cyan(integrations.join(', '))}`));\n }\n console.log();\n}\n","import path from 'path';\nimport chalk from 'chalk';\nimport type { ProjectConfig, EnvEntry } from '../types/config.js';\nimport type { InstallerOptions } from '../types/installers.js';\nimport { generateBase } from './base.js';\nimport { generateFrontend } from './frontend.js';\nimport { generateBackend } from './backend.js';\nimport { generateDocker } from './docker.js';\nimport { generateEnv } from './env.js';\nimport { generateReadme } from './readme.js';\nimport { generateWiring } from './wiring.js';\nimport { generateLiz } from './liz.js';\nimport { buildInstallerMap } from '../installers/index.js';\nimport { withSpinner } from '../helpers/spinner.js';\nimport { installDependencies } from '../helpers/runtime.js';\nimport { initGit } from '../helpers/git.js';\nimport { logger } from '../helpers/logger.js';\nimport { readPackageJson, writePackageJson, sortDeps } from '../helpers/packages.js';\nimport { getRunCommand } from '../helpers/runtime.js';\n\nexport async function generateProject(config: ProjectConfig): Promise<void> {\n const projectDir = config.projectDir;\n const apiDir = path.join(projectDir, 'apps', 'api');\n const webDir = path.join(projectDir, 'apps', 'web');\n\n const envEntries: EnvEntry[] = [];\n const dependencies: Record<string, string> = {};\n const devDependencies: Record<string, string> = {};\n const scripts: Record<string, string> = {};\n const dockerServices: string[] = [];\n\n const opts: InstallerOptions = {\n config,\n projectDir,\n apiDir,\n webDir,\n envEntries,\n dependencies,\n devDependencies,\n scripts,\n dockerServices,\n };\n\n console.log(chalk.cyan('\\n Liz está preparando seu projeto...\\n'));\n\n // 1. Base monorepo structure\n await withSpinner('Criando estrutura do monorepo...', async () => {\n await generateBase(config);\n });\n\n // 2. Frontend\n await withSpinner(`Configurando frontend (${config.frontend})...`, async () => {\n await generateFrontend(config, webDir);\n });\n\n // 3. Backend\n await withSpinner(`Configurando backend (${config.backend})...`, async () => {\n await generateBackend(config, apiDir);\n });\n\n // 4. Run installers\n const installerMap = buildInstallerMap(config);\n for (const [name, entry] of Object.entries(installerMap)) {\n if (entry.inUse) {\n await withSpinner(`Configurando ${name}...`, async () => {\n await entry.installer(opts);\n });\n }\n }\n\n // 5. Merge accumulated dependencies into API package.json\n if (Object.keys(dependencies).length > 0 || Object.keys(devDependencies).length > 0 || Object.keys(scripts).length > 0) {\n const apiPkg = await readPackageJson(apiDir);\n if (!apiPkg.dependencies) apiPkg.dependencies = {};\n if (!apiPkg.devDependencies) apiPkg.devDependencies = {};\n if (!apiPkg.scripts) apiPkg.scripts = {};\n Object.assign(apiPkg.dependencies, dependencies);\n Object.assign(apiPkg.devDependencies, devDependencies);\n Object.assign(apiPkg.scripts, scripts);\n await writePackageJson(apiDir, sortDeps(apiPkg));\n }\n\n // 6. Auto-wiring: connect all modules in the main app file\n await withSpinner('Conectando módulos automaticamente...', async () => {\n await generateWiring(config, apiDir);\n });\n\n // 7. Docker compose\n if (config.database !== 'none' || config.redis || config.queue === 'rabbitmq' || config.minio) {\n await withSpinner('Gerando docker-compose.yml...', async () => {\n await generateDocker(config, projectDir, dockerServices);\n });\n }\n\n // 8. Environment files\n await withSpinner('Gerando arquivos .env...', async () => {\n await generateEnv(config, apiDir, envEntries);\n });\n\n // 9. README\n await withSpinner('Gerando README.md...', async () => {\n await generateReadme(config, projectDir);\n });\n\n // 10. Liz - AI Agent config\n await withSpinner('Configurando Liz (AI Agent)...', async () => {\n await generateLiz(config, projectDir);\n });\n\n // 11. Install dependencies\n let installResult: { success: boolean; fallback?: string } = { success: false };\n try {\n await withSpinner(`Instalando dependências (${config.runtime})...`, async () => {\n installResult = await installDependencies(projectDir, config.runtime);\n });\n if (installResult.fallback) {\n logger.warn(`${config.runtime} não encontrado. Dependências instaladas com ${installResult.fallback}.`);\n }\n } catch {\n logger.warn(`Não foi possível instalar dependências automaticamente.`);\n logger.info(`Rode manualmente: cd ${config.projectName} && ${config.runtime} install`);\n }\n\n // 12. Git init\n try {\n await withSpinner('Inicializando repositório git...', async () => {\n await initGit(projectDir);\n });\n } catch {\n logger.warn('Git não encontrado. Inicialize manualmente com: git init');\n }\n\n // 13. Print success & next steps\n printNextSteps(config, installResult.success);\n}\n\nfunction printNextSteps(config: ProjectConfig, depsInstalled = true): void {\n const runCmd = getRunCommand(config.runtime);\n const hasDocker = config.database !== 'none' || config.redis || config.queue === 'rabbitmq' || config.minio;\n\n const authMethods = [\n config.auth.jwt && 'JWT',\n config.auth.magicLink && 'Magic Link',\n config.auth.googleOAuth && 'Google OAuth',\n ].filter(Boolean);\n\n const integrations = Object.entries(config.integrations)\n .filter(([, v]) => v)\n .map(([k]) => k);\n\n console.log(\n chalk.bold.green(`\n ╔═══════════════════════════════════════════════════╗\n ║ ║\n ║ ✅ Projeto \"${config.projectName}\" criado! ║\n ║ Tudo configurado pela Liz ║\n ║ ║\n ╚═══════════════════════════════════════════════════╝\n`)\n );\n\n // Show what was auto-configured\n console.log(chalk.bold.white(' O que a Liz configurou pra você:\\n'));\n\n console.log(chalk.green(' ✔ ') + chalk.white(`Frontend ${chalk.cyan(config.frontend)} pronto em apps/web/`));\n console.log(chalk.green(' ✔ ') + chalk.white(`Backend ${chalk.cyan(config.backend)} pronto em apps/api/`));\n\n if (config.database !== 'none') {\n console.log(chalk.green(' ✔ ') + chalk.white(`Banco ${chalk.cyan(config.database)} configurado com nome \"${chalk.cyan(config.projectName.replace(/-/g, '_'))}\"`));\n }\n if (authMethods.length > 0) {\n console.log(chalk.green(' ✔ ') + chalk.white(`Autenticação: ${chalk.cyan(authMethods.join(', '))} com rotas prontas`));\n }\n if (config.redis) {\n console.log(chalk.green(' ✔ ') + chalk.white(`Redis configurado e conectado`));\n }\n if (config.queue !== 'none') {\n console.log(chalk.green(' ✔ ') + chalk.white(`Filas ${chalk.cyan(config.queue)} com worker de exemplo`));\n }\n if (config.smtp) {\n console.log(chalk.green(' ✔ ') + chalk.white(`SMTP com serviço de email e template HTML`));\n }\n if (config.minio) {\n console.log(chalk.green(' ✔ ') + chalk.white(`MinIO storage com upload/download prontos`));\n }\n if (config.multiTenant) {\n console.log(chalk.green(' ✔ ') + chalk.white(`Multi-tenant com middleware de isolamento`));\n }\n if (config.pm2) {\n console.log(chalk.green(' ✔ ') + chalk.white(`PM2 com cluster mode para zero-downtime`));\n }\n if (integrations.length > 0) {\n console.log(chalk.green(' ✔ ') + chalk.white(`Integrações: ${chalk.cyan(integrations.join(', '))}`));\n }\n console.log(chalk.green(' ✔ ') + chalk.white(`Liz (AI Agent) configurada para te ajudar`));\n\n if (hasDocker) {\n console.log(chalk.green(' ✔ ') + chalk.white(`Docker Compose com todos os serviços`));\n }\n\n console.log(chalk.bold.white('\\n Próximos passos:\\n'));\n\n let step = 1;\n console.log(chalk.white(` ${step}. ${chalk.cyan(`cd ${config.projectName}`)}`));\n step++;\n\n if (!depsInstalled) {\n console.log(chalk.white(` ${step}. ${chalk.cyan(`${config.runtime} install`)}`));\n console.log(chalk.gray(' Instala as dependências do projeto'));\n step++;\n }\n\n if (hasDocker) {\n console.log(chalk.white(` ${step}. ${chalk.cyan('docker compose up -d')}`));\n console.log(chalk.gray(' Sobe banco, redis, minio, etc em containers'));\n step++;\n }\n\n if (config.usePrisma) {\n console.log(chalk.white(` ${step}. ${chalk.cyan('cd apps/api && npx prisma db push && cd ../..')}`));\n console.log(chalk.gray(' Cria as tabelas no banco de dados'));\n step++;\n }\n\n console.log(chalk.white(` ${step}. ${chalk.cyan(`${runCmd} dev`)}`));\n console.log(chalk.gray(' Inicia frontend e API em modo desenvolvimento'));\n\n console.log(chalk.bold.white('\\n URLs:\\n'));\n console.log(chalk.white(` Frontend: ${chalk.cyan('http://localhost:3000')}`));\n console.log(chalk.white(` API: ${chalk.cyan('http://localhost:3001')}`));\n console.log(chalk.white(` Health: ${chalk.cyan('http://localhost:3001/api/health')}`));\n if (config.usePrisma) {\n console.log(chalk.white(` DB Studio: ${chalk.cyan('npx prisma studio')} (na pasta apps/api)`));\n }\n if (config.queue === 'rabbitmq') {\n console.log(chalk.white(` RabbitMQ: ${chalk.cyan('http://localhost:15672')} (guest/guest)`));\n }\n if (config.minio) {\n console.log(chalk.white(` MinIO: ${chalk.cyan('http://localhost:9001')} (minioadmin/minioadmin)`));\n }\n\n if (config.pm2) {\n console.log(chalk.bold.white('\\n Produção com PM2:\\n'));\n console.log(chalk.white(` ${chalk.cyan(`${runCmd} build`)} && ${chalk.cyan('pm2 start ecosystem.config.cjs')}`));\n }\n\n console.log(chalk.gray(`\\n Precisa de ajuda? A Liz está disponível no seu editor.`));\n console.log(chalk.gray(` Documentação: https://github.com/pablocarss/plazercli\\n`));\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { ensureDir, writeFile, copyFile, getTemplatePath } from '../helpers/filesystem.js';\nimport { renderTemplate } from '../helpers/template.js';\nimport { getRunCommand } from '../helpers/runtime.js';\n\nexport async function generateBase(config: ProjectConfig): Promise<void> {\n const { projectDir, projectName, projectDescription, runtime } = config;\n\n // Create root directories\n await ensureDir(projectDir);\n await ensureDir(path.join(projectDir, 'apps'));\n await ensureDir(path.join(projectDir, 'apps', 'api'));\n await ensureDir(path.join(projectDir, 'apps', 'web'));\n\n // Render root package.json\n const runCmd = getRunCommand(runtime);\n const packageJsonTemplate = getTemplatePath('base', 'root', 'package.json.ejs');\n const packageJsonContent = await renderTemplate(packageJsonTemplate, {\n projectName,\n projectDescription,\n runCmd,\n });\n await writeFile(path.join(projectDir, 'package.json'), packageJsonContent);\n\n // Copy static root files\n await copyFile(\n getTemplatePath('base', 'root', 'gitignore'),\n path.join(projectDir, '.gitignore')\n );\n await copyFile(\n getTemplatePath('base', 'root', 'editorconfig'),\n path.join(projectDir, '.editorconfig')\n );\n await copyFile(\n getTemplatePath('base', 'root', 'nvmrc'),\n path.join(projectDir, '.nvmrc')\n );\n\n // pnpm-workspace.yaml only for pnpm\n if (runtime === 'pnpm') {\n await copyFile(\n getTemplatePath('base', 'root', 'pnpm-workspace.yaml'),\n path.join(projectDir, 'pnpm-workspace.yaml')\n );\n }\n}\n","import fs from 'fs-extra';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n// Resolve templates dir from both src/helpers/ (dev) and dist/ (built)\nconst TEMPLATE_DIR = fs.existsSync(path.resolve(__dirname, '../../templates'))\n ? path.resolve(__dirname, '../../templates')\n : path.resolve(__dirname, '../templates');\n\nexport function getTemplatePath(...segments: string[]): string {\n return path.join(TEMPLATE_DIR, ...segments);\n}\n\nexport async function ensureDir(dir: string): Promise<void> {\n await fs.ensureDir(dir);\n}\n\nexport async function copyDir(src: string, dest: string): Promise<void> {\n await fs.copy(src, dest, { overwrite: true });\n}\n\nexport async function copyFile(src: string, dest: string): Promise<void> {\n await fs.ensureDir(path.dirname(dest));\n await fs.copyFile(src, dest);\n}\n\nexport async function writeFile(filePath: string, content: string): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\nexport async function readFile(filePath: string): Promise<string> {\n return fs.readFile(filePath, 'utf-8');\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n return fs.pathExists(filePath);\n}\n","import ejs from 'ejs';\nimport { readFile, writeFile, getTemplatePath } from './filesystem.js';\nimport path from 'path';\n\nexport async function renderTemplate(\n templatePath: string,\n data: Record<string, unknown>\n): Promise<string> {\n const template = await readFile(templatePath);\n return ejs.render(template, data, { async: false });\n}\n\nexport async function renderTemplateToFile(\n templateRelativePath: string,\n destPath: string,\n data: Record<string, unknown>\n): Promise<void> {\n const templatePath = getTemplatePath(templateRelativePath);\n const rendered = await renderTemplate(templatePath, data);\n\n // Remove .ejs extension from destination if present\n const finalDest = destPath.endsWith('.ejs')\n ? destPath.slice(0, -4)\n : destPath;\n\n await writeFile(finalDest, rendered);\n}\n\nexport async function renderAndWrite(\n templateDir: string,\n destDir: string,\n fileName: string,\n data: Record<string, unknown>\n): Promise<void> {\n const templatePath = path.join(templateDir, `${fileName}.ejs`);\n const rendered = await renderTemplate(templatePath, data);\n await writeFile(path.join(destDir, fileName), rendered);\n}\n","import { execa } from 'execa';\nimport type { ProjectConfig } from '../types/config.js';\n\nexport function getInstallCommand(runtime: ProjectConfig['runtime']): [string, string[]] {\n switch (runtime) {\n case 'bun':\n return ['bun', ['install']];\n case 'pnpm':\n return ['pnpm', ['install']];\n case 'npm':\n return ['npm', ['install']];\n }\n}\n\nexport function getRunCommand(runtime: ProjectConfig['runtime']): string {\n switch (runtime) {\n case 'bun':\n return 'bun run';\n case 'pnpm':\n return 'pnpm run';\n case 'npm':\n return 'npm run';\n }\n}\n\nasync function isCommandAvailable(cmd: string): Promise<boolean> {\n try {\n await execa('which', [cmd]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function installDependencies(\n projectDir: string,\n runtime: ProjectConfig['runtime']\n): Promise<{ success: boolean; fallback?: string }> {\n const [cmd, args] = getInstallCommand(runtime);\n\n // Check if selected runtime is available\n if (await isCommandAvailable(cmd)) {\n await execa(cmd, args, { cwd: projectDir, stdio: 'pipe' });\n return { success: true };\n }\n\n // Try fallback runtimes\n const fallbacks: ProjectConfig['runtime'][] = ['npm', 'pnpm', 'bun'];\n for (const fb of fallbacks) {\n if (fb === runtime) continue;\n const [fbCmd, fbArgs] = getInstallCommand(fb);\n if (await isCommandAvailable(fbCmd)) {\n await execa(fbCmd, fbArgs, { cwd: projectDir, stdio: 'pipe' });\n return { success: true, fallback: fb };\n }\n }\n\n return { success: false };\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile, ensureDir } from '../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../installers/dependencyVersionMap.js';\n\nexport async function generateFrontend(config: ProjectConfig, webDir: string): Promise<void> {\n switch (config.frontend) {\n case 'nextjs':\n await generateNextjs(config, webDir);\n break;\n case 'react-vite':\n await generateReactVite(config, webDir);\n break;\n case 'vue':\n await generateVue(config, webDir);\n break;\n case 'angular':\n await generateAngular(config, webDir);\n break;\n }\n}\n\nasync function generateNextjs(config: ProjectConfig, webDir: string): Promise<void> {\n await ensureDir(path.join(webDir, 'src', 'app'));\n await ensureDir(path.join(webDir, 'public'));\n\n await writeFile(path.join(webDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/web`,\n version: '0.1.0',\n private: true,\n scripts: {\n dev: 'next dev',\n build: 'next build',\n start: 'next start',\n lint: 'next lint',\n },\n dependencies: {\n next: deps.next,\n react: deps.react,\n 'react-dom': deps['react-dom'],\n },\n devDependencies: {\n '@types/node': deps['@types/node'],\n '@types/react': deps['@types/react'],\n '@types/react-dom': deps['@types/react-dom'],\n typescript: deps.typescript,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2017',\n lib: ['dom', 'dom.iterable', 'esnext'],\n allowJs: true,\n skipLibCheck: true,\n strict: true,\n noEmit: true,\n esModuleInterop: true,\n module: 'esnext',\n moduleResolution: 'bundler',\n resolveJsonModule: true,\n isolatedModules: true,\n jsx: 'preserve',\n incremental: true,\n plugins: [{ name: 'next' }],\n paths: { '@/*': ['./src/*'] },\n },\n include: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],\n exclude: ['node_modules'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'next.config.ts'), `import type { NextConfig } from 'next';\n\nconst nextConfig: NextConfig = {};\n\nexport default nextConfig;\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'layout.tsx'), `import type { Metadata } from 'next';\nimport './globals.css';\n\nexport const metadata: Metadata = {\n title: '${config.projectName}',\n description: '${config.projectDescription}',\n};\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <html lang=\"pt-BR\">\n <body>{children}</body>\n </html>\n );\n}\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'page.tsx'), `export default function Home() {\n return (\n <main style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', fontFamily: 'system-ui' }}>\n <h1>${config.projectName}</h1>\n <p>${config.projectDescription}</p>\n <p style={{ marginTop: '2rem', color: '#666' }}>\n API rodando em <a href=\"http://localhost:3001\" style={{ color: '#0070f3' }}>http://localhost:3001</a>\n </p>\n </main>\n );\n}\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'globals.css'), `* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: system-ui, -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n\na {\n color: inherit;\n text-decoration: none;\n}\n`);\n}\n\nasync function generateReactVite(config: ProjectConfig, webDir: string): Promise<void> {\n await ensureDir(path.join(webDir, 'src'));\n await ensureDir(path.join(webDir, 'public'));\n\n await writeFile(path.join(webDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/web`,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n dev: 'vite',\n build: 'tsc -b && vite build',\n preview: 'vite preview',\n },\n dependencies: {\n react: deps.react,\n 'react-dom': deps['react-dom'],\n },\n devDependencies: {\n '@types/react': deps['@types/react'],\n '@types/react-dom': deps['@types/react-dom'],\n '@vitejs/plugin-react': '^4.3.0',\n typescript: deps.typescript,\n vite: deps.vite,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2020',\n useDefineForClassFields: true,\n lib: ['ES2020', 'DOM', 'DOM.Iterable'],\n module: 'ESNext',\n skipLibCheck: true,\n moduleResolution: 'bundler',\n allowImportingTsExtensions: true,\n isolatedModules: true,\n noEmit: true,\n jsx: 'react-jsx',\n strict: true,\n },\n include: ['src'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'vite.config.ts'), `import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\nexport default defineConfig({\n plugins: [react()],\n server: {\n port: 3000,\n },\n});\n`);\n\n await writeFile(path.join(webDir, 'index.html'), `<!doctype html>\n<html lang=\"pt-BR\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${config.projectName}</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"></script>\n </body>\n</html>\n`);\n\n await writeFile(path.join(webDir, 'src', 'main.tsx'), `import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\nimport './index.css';\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <App />\n </React.StrictMode>,\n);\n`);\n\n await writeFile(path.join(webDir, 'src', 'App.tsx'), `function App() {\n return (\n <main style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', fontFamily: 'system-ui' }}>\n <h1>${config.projectName}</h1>\n <p>${config.projectDescription}</p>\n <p style={{ marginTop: '2rem', color: '#666' }}>\n API rodando em <a href=\"http://localhost:3001\" style={{ color: '#0070f3' }}>http://localhost:3001</a>\n </p>\n </main>\n );\n}\n\nexport default App;\n`);\n\n await writeFile(path.join(webDir, 'src', 'index.css'), `* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: system-ui, -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n`);\n}\n\nasync function generateVue(config: ProjectConfig, webDir: string): Promise<void> {\n await ensureDir(path.join(webDir, 'src'));\n await ensureDir(path.join(webDir, 'public'));\n\n await writeFile(path.join(webDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/web`,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n dev: 'vite',\n build: 'vue-tsc -b && vite build',\n preview: 'vite preview',\n },\n dependencies: {\n vue: deps.vue,\n 'vue-router': deps['vue-router'],\n },\n devDependencies: {\n '@vitejs/plugin-vue': deps['@vitejs/plugin-vue'],\n typescript: deps.typescript,\n vite: deps.vite,\n 'vue-tsc': '^2.1.0',\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n lib: ['ES2020', 'DOM', 'DOM.Iterable'],\n skipLibCheck: true,\n moduleResolution: 'bundler',\n allowImportingTsExtensions: true,\n isolatedModules: true,\n noEmit: true,\n jsx: 'preserve',\n strict: true,\n },\n include: ['src/**/*.ts', 'src/**/*.vue'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'vite.config.ts'), `import { defineConfig } from 'vite';\nimport vue from '@vitejs/plugin-vue';\n\nexport default defineConfig({\n plugins: [vue()],\n server: {\n port: 3000,\n },\n});\n`);\n\n await writeFile(path.join(webDir, 'index.html'), `<!doctype html>\n<html lang=\"pt-BR\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${config.projectName}</title>\n </head>\n <body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/src/main.ts\"></script>\n </body>\n</html>\n`);\n\n await writeFile(path.join(webDir, 'src', 'main.ts'), `import { createApp } from 'vue';\nimport App from './App.vue';\nimport './style.css';\n\ncreateApp(App).mount('#app');\n`);\n\n await writeFile(path.join(webDir, 'src', 'App.vue'), `<template>\n <main class=\"container\">\n <h1>${config.projectName}</h1>\n <p>${config.projectDescription}</p>\n <p class=\"api-link\">\n API rodando em <a href=\"http://localhost:3001\">http://localhost:3001</a>\n </p>\n </main>\n</template>\n\n<style scoped>\n.container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n font-family: system-ui;\n}\n.api-link {\n margin-top: 2rem;\n color: #666;\n}\n.api-link a {\n color: #42b883;\n}\n</style>\n`);\n\n await writeFile(path.join(webDir, 'src', 'style.css'), `* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: system-ui, -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n`);\n\n await writeFile(path.join(webDir, 'env.d.ts'), `/// <reference types=\"vite/client\" />\n`);\n}\n\nasync function generateAngular(config: ProjectConfig, webDir: string): Promise<void> {\n await ensureDir(path.join(webDir, 'src', 'app'));\n\n await writeFile(path.join(webDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/web`,\n version: '0.1.0',\n private: true,\n scripts: {\n dev: 'ng serve --port 3000',\n build: 'ng build',\n lint: 'ng lint',\n },\n dependencies: {\n '@angular/animations': deps['@angular/core'],\n '@angular/common': deps['@angular/core'],\n '@angular/compiler': deps['@angular/core'],\n '@angular/core': deps['@angular/core'],\n '@angular/forms': deps['@angular/core'],\n '@angular/platform-browser': deps['@angular/core'],\n '@angular/platform-browser-dynamic': deps['@angular/core'],\n '@angular/router': deps['@angular/core'],\n rxjs: deps.rxjs,\n 'zone.js': '^0.15.0',\n },\n devDependencies: {\n '@angular/cli': deps['@angular/cli'],\n '@angular/compiler-cli': deps['@angular/core'],\n typescript: deps.typescript,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2022',\n module: 'ES2022',\n lib: ['ES2022', 'dom'],\n skipLibCheck: true,\n moduleResolution: 'bundler',\n strict: true,\n noEmit: false,\n declaration: false,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n outDir: './dist',\n },\n include: ['src/**/*.ts'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'angular.json'), JSON.stringify({\n $schema: './node_modules/@angular/cli/lib/config/schema.json',\n version: 1,\n newProjectRoot: 'projects',\n projects: {\n web: {\n projectType: 'application',\n root: '',\n sourceRoot: 'src',\n architect: {\n build: {\n builder: '@angular-devkit/build-angular:application',\n options: {\n outputPath: 'dist',\n index: 'src/index.html',\n browser: 'src/main.ts',\n tsConfig: 'tsconfig.json',\n },\n },\n serve: {\n builder: '@angular-devkit/build-angular:dev-server',\n configurations: {\n development: { buildTarget: 'web:build' },\n },\n defaultConfiguration: 'development',\n },\n },\n },\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'src', 'index.html'), `<!doctype html>\n<html lang=\"pt-BR\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${config.projectName}</title>\n </head>\n <body>\n <app-root></app-root>\n </body>\n</html>\n`);\n\n await writeFile(path.join(webDir, 'src', 'main.ts'), `import { bootstrapApplication } from '@angular/platform-browser';\nimport { AppComponent } from './app/app.component';\n\nbootstrapApplication(AppComponent).catch((err) => console.error(err));\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'app.component.ts'), `import { Component } from '@angular/core';\n\n@Component({\n selector: 'app-root',\n standalone: true,\n template: \\`\n <main style=\"display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; font-family: system-ui;\">\n <h1>${config.projectName}</h1>\n <p>${config.projectDescription}</p>\n <p style=\"margin-top: 2rem; color: #666;\">\n API rodando em <a href=\"http://localhost:3001\" style=\"color: #dd0031;\">http://localhost:3001</a>\n </p>\n </main>\n \\`,\n})\nexport class AppComponent {}\n`);\n\n await writeFile(path.join(webDir, 'src', 'styles.css'), `* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: system-ui, -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n`);\n}\n","export const dependencyVersionMap = {\n // Prisma\n 'prisma': '^6.3.0',\n '@prisma/client': '^6.3.0',\n\n // Mongoose\n 'mongoose': '^8.9.0',\n\n // Auth\n 'jsonwebtoken': '^9.0.2',\n '@types/jsonwebtoken': '^9.0.7',\n 'bcryptjs': '^2.4.3',\n '@types/bcryptjs': '^2.4.6',\n 'passport': '^0.7.0',\n 'passport-jwt': '^4.0.1',\n '@types/passport-jwt': '^4.0.1',\n 'passport-google-oauth20': '^2.0.0',\n '@types/passport-google-oauth20': '^2.0.16',\n '@nestjs/jwt': '^11.0.0',\n '@nestjs/passport': '^11.0.0',\n 'nanoid': '^5.0.9',\n\n // Queues\n 'bullmq': '^5.30.0',\n '@nestjs/bullmq': '^11.0.0',\n 'amqplib': '^0.10.5',\n '@types/amqplib': '^0.10.6',\n\n // Redis\n 'ioredis': '^5.4.0',\n\n // SMTP\n 'nodemailer': '^6.9.0',\n '@types/nodemailer': '^6.4.17',\n\n // Storage\n 'minio': '^8.0.0',\n\n // Integrations\n 'axios': '^1.7.0',\n 'stripe': '^17.4.0',\n 'mercadopago': '^2.0.0',\n\n // Express\n 'express': '^4.21.0',\n '@types/express': '^4.17.21',\n 'cors': '^2.8.5',\n '@types/cors': '^2.8.17',\n 'helmet': '^8.0.0',\n 'dotenv': '^16.4.0',\n\n // Fastify\n '@fastify/cors': '^10.0.0',\n '@fastify/helmet': '^12.0.0',\n 'fastify': '^5.0.0',\n\n // NestJS\n '@nestjs/common': '^11.0.0',\n '@nestjs/core': '^11.0.0',\n '@nestjs/platform-express': '^11.0.0',\n '@nestjs/config': '^4.0.0',\n '@nestjs/cli': '^11.0.0',\n 'reflect-metadata': '^0.2.2',\n 'rxjs': '^7.8.1',\n\n // Next.js\n 'next': '^15.0.0',\n 'react': '^19.0.0',\n 'react-dom': '^19.0.0',\n '@types/react': '^19.0.0',\n '@types/react-dom': '^19.0.0',\n\n // Vue\n 'vue': '^3.5.0',\n 'vue-router': '^4.5.0',\n '@vitejs/plugin-vue': '^5.0.0',\n\n // Angular\n '@angular/core': '^19.0.0',\n '@angular/cli': '^19.0.0',\n\n // Common\n 'typescript': '^5.7.0',\n 'vite': '^6.0.0',\n '@types/node': '^22.10.0',\n 'tsx': '^4.19.0',\n 'pm2': '^5.4.0',\n} as const;\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile, ensureDir } from '../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../installers/dependencyVersionMap.js';\n\nexport async function generateBackend(config: ProjectConfig, apiDir: string): Promise<void> {\n switch (config.backend) {\n case 'express':\n await generateExpress(config, apiDir);\n break;\n case 'fastify':\n await generateFastify(config, apiDir);\n break;\n case 'nestjs':\n await generateNestjs(config, apiDir);\n break;\n }\n}\n\nasync function generateExpress(config: ProjectConfig, apiDir: string): Promise<void> {\n await ensureDir(path.join(apiDir, 'src', 'routes'));\n await ensureDir(path.join(apiDir, 'src', 'middlewares'));\n await ensureDir(path.join(apiDir, 'src', 'config'));\n\n await writeFile(path.join(apiDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/api`,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n dev: 'tsx watch src/index.ts',\n build: 'tsc',\n start: 'node dist/index.js',\n lint: 'tsc --noEmit',\n },\n dependencies: {\n express: deps.express,\n cors: deps.cors,\n helmet: deps.helmet,\n dotenv: deps.dotenv,\n },\n devDependencies: {\n '@types/express': deps['@types/express'],\n '@types/cors': deps['@types/cors'],\n '@types/node': deps['@types/node'],\n typescript: deps.typescript,\n tsx: deps.tsx,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n esModuleInterop: true,\n strict: true,\n outDir: 'dist',\n rootDir: 'src',\n skipLibCheck: true,\n declaration: true,\n },\n include: ['src/**/*'],\n exclude: ['node_modules', 'dist'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'src', 'config', 'index.ts'), `import 'dotenv/config';\n\nexport const config = {\n port: Number(process.env.PORT) || 3001,\n nodeEnv: process.env.NODE_ENV || 'development',\n corsOrigin: process.env.CORS_ORIGIN || 'http://localhost:3000',\n};\n`);\n\n await writeFile(path.join(apiDir, 'src', 'app.ts'), `import express from 'express';\nimport cors from 'cors';\nimport helmet from 'helmet';\nimport { config } from './config/index.js';\nimport { router } from './routes/index.js';\nimport { errorHandler } from './middlewares/errorHandler.js';\n\nconst app = express();\n\napp.use(helmet());\napp.use(cors({ origin: config.corsOrigin }));\napp.use(express.json());\n\napp.use('/api', router);\n\napp.use(errorHandler);\n\nexport { app };\n`);\n\n await writeFile(path.join(apiDir, 'src', 'index.ts'), `import { app } from './app.js';\nimport { config } from './config/index.js';\n\napp.listen(config.port, () => {\n console.log(\\`🚀 API rodando em http://localhost:\\${config.port}\\`);\n});\n`);\n\n await writeFile(path.join(apiDir, 'src', 'routes', 'index.ts'), `import { Router } from 'express';\n\nconst router = Router();\n\nrouter.get('/health', (_req, res) => {\n res.json({ status: 'ok', timestamp: new Date().toISOString() });\n});\n\nexport { router };\n`);\n\n await writeFile(path.join(apiDir, 'src', 'middlewares', 'errorHandler.ts'), `import type { Request, Response, NextFunction } from 'express';\n\nexport function errorHandler(err: Error, _req: Request, res: Response, _next: NextFunction) {\n console.error(err.stack);\n res.status(500).json({\n error: 'Internal Server Error',\n message: process.env.NODE_ENV === 'development' ? err.message : undefined,\n });\n}\n`);\n}\n\nasync function generateFastify(config: ProjectConfig, apiDir: string): Promise<void> {\n await ensureDir(path.join(apiDir, 'src', 'routes'));\n await ensureDir(path.join(apiDir, 'src', 'plugins'));\n await ensureDir(path.join(apiDir, 'src', 'config'));\n\n await writeFile(path.join(apiDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/api`,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n dev: 'tsx watch src/index.ts',\n build: 'tsc',\n start: 'node dist/index.js',\n lint: 'tsc --noEmit',\n },\n dependencies: {\n fastify: deps.fastify,\n '@fastify/cors': deps['@fastify/cors'],\n '@fastify/helmet': deps['@fastify/helmet'],\n dotenv: deps.dotenv,\n },\n devDependencies: {\n '@types/node': deps['@types/node'],\n typescript: deps.typescript,\n tsx: deps.tsx,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n esModuleInterop: true,\n strict: true,\n outDir: 'dist',\n rootDir: 'src',\n skipLibCheck: true,\n declaration: true,\n },\n include: ['src/**/*'],\n exclude: ['node_modules', 'dist'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'src', 'config', 'index.ts'), `import 'dotenv/config';\n\nexport const config = {\n port: Number(process.env.PORT) || 3001,\n host: process.env.HOST || '0.0.0.0',\n nodeEnv: process.env.NODE_ENV || 'development',\n corsOrigin: process.env.CORS_ORIGIN || 'http://localhost:3000',\n};\n`);\n\n await writeFile(path.join(apiDir, 'src', 'app.ts'), `import Fastify from 'fastify';\nimport cors from '@fastify/cors';\nimport helmet from '@fastify/helmet';\nimport { config } from './config/index.js';\nimport { registerRoutes } from './routes/index.js';\n\nexport async function buildApp() {\n const app = Fastify({\n logger: config.nodeEnv === 'development',\n });\n\n await app.register(helmet);\n await app.register(cors, { origin: config.corsOrigin });\n\n registerRoutes(app);\n\n return app;\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'index.ts'), `import { buildApp } from './app.js';\nimport { config } from './config/index.js';\n\nasync function start() {\n const app = await buildApp();\n\n await app.listen({ port: config.port, host: config.host });\n console.log(\\`🚀 API rodando em http://localhost:\\${config.port}\\`);\n}\n\nstart().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n`);\n\n await writeFile(path.join(apiDir, 'src', 'routes', 'index.ts'), `import type { FastifyInstance } from 'fastify';\n\nexport function registerRoutes(app: FastifyInstance) {\n app.get('/api/health', async () => {\n return { status: 'ok', timestamp: new Date().toISOString() };\n });\n}\n`);\n}\n\nasync function generateNestjs(config: ProjectConfig, apiDir: string): Promise<void> {\n await ensureDir(path.join(apiDir, 'src'));\n\n await writeFile(path.join(apiDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/api`,\n version: '0.1.0',\n private: true,\n scripts: {\n dev: 'nest start --watch',\n build: 'nest build',\n start: 'node dist/main.js',\n 'start:prod': 'node dist/main.js',\n lint: 'tsc --noEmit',\n },\n dependencies: {\n '@nestjs/common': deps['@nestjs/common'],\n '@nestjs/core': deps['@nestjs/core'],\n '@nestjs/platform-express': deps['@nestjs/platform-express'],\n '@nestjs/config': deps['@nestjs/config'],\n 'reflect-metadata': deps['reflect-metadata'],\n rxjs: deps.rxjs,\n },\n devDependencies: {\n '@nestjs/cli': deps['@nestjs/cli'],\n '@types/node': deps['@types/node'],\n typescript: deps.typescript,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n module: 'commonjs',\n declaration: true,\n removeComments: true,\n emitDecoratorMetadata: true,\n experimentalDecorators: true,\n allowSyntheticDefaultImports: true,\n target: 'ES2021',\n sourceMap: true,\n outDir: './dist',\n rootDir: './src',\n strict: true,\n skipLibCheck: true,\n },\n include: ['src/**/*'],\n exclude: ['node_modules', 'dist'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'nest-cli.json'), JSON.stringify({\n $schema: 'https://json.schemastore.org/nest-cli',\n collection: '@nestjs/schematics',\n sourceRoot: 'src',\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'src', 'main.ts'), `import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n const app = await NestFactory.create(AppModule);\n app.enableCors({ origin: process.env.CORS_ORIGIN || 'http://localhost:3000' });\n app.setGlobalPrefix('api');\n\n const port = process.env.PORT || 3001;\n await app.listen(port);\n console.log(\\`🚀 API rodando em http://localhost:\\${port}\\`);\n}\n\nbootstrap();\n`);\n\n await writeFile(path.join(apiDir, 'src', 'app.module.ts'), `import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n imports: [\n ConfigModule.forRoot({ isGlobal: true }),\n ],\n controllers: [AppController],\n providers: [AppService],\n})\nexport class AppModule {}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'app.controller.ts'), `import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n constructor(private readonly appService: AppService) {}\n\n @Get('health')\n getHealth() {\n return this.appService.getHealth();\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'app.service.ts'), `import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n getHealth() {\n return { status: 'ok', timestamp: new Date().toISOString() };\n }\n}\n`);\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile } from '../helpers/filesystem.js';\n\nexport async function generateDocker(\n config: ProjectConfig,\n projectDir: string,\n extraServices: string[]\n): Promise<void> {\n const services: string[] = [];\n\n // Database services\n if (config.database === 'postgresql') {\n services.push(` postgres:\n image: postgres:16-alpine\n container_name: ${config.projectName}-postgres\n restart: unless-stopped\n environment:\n POSTGRES_USER: postgres\n POSTGRES_PASSWORD: postgres\n POSTGRES_DB: ${config.projectName.replace(/-/g, '_')}\n ports:\n - \"5432:5432\"\n volumes:\n - postgres_data:/var/lib/postgresql/data`);\n }\n\n if (config.database === 'mysql') {\n services.push(` mysql:\n image: mysql:8\n container_name: ${config.projectName}-mysql\n restart: unless-stopped\n environment:\n MYSQL_ROOT_PASSWORD: root\n MYSQL_DATABASE: ${config.projectName.replace(/-/g, '_')}\n MYSQL_USER: user\n MYSQL_PASSWORD: password\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql`);\n }\n\n if (config.database === 'mongodb') {\n services.push(` mongodb:\n image: mongo:7\n container_name: ${config.projectName}-mongodb\n restart: unless-stopped\n environment:\n MONGO_INITDB_ROOT_USERNAME: root\n MONGO_INITDB_ROOT_PASSWORD: root\n MONGO_INITDB_DATABASE: ${config.projectName.replace(/-/g, '_')}\n ports:\n - \"27017:27017\"\n volumes:\n - mongodb_data:/data/db`);\n }\n\n // Redis\n if (config.redis) {\n services.push(` redis:\n image: redis:7-alpine\n container_name: ${config.projectName}-redis\n restart: unless-stopped\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data`);\n }\n\n // RabbitMQ\n if (config.queue === 'rabbitmq') {\n services.push(` rabbitmq:\n image: rabbitmq:3-management-alpine\n container_name: ${config.projectName}-rabbitmq\n restart: unless-stopped\n environment:\n RABBITMQ_DEFAULT_USER: guest\n RABBITMQ_DEFAULT_PASS: guest\n ports:\n - \"5672:5672\"\n - \"15672:15672\"\n volumes:\n - rabbitmq_data:/var/lib/rabbitmq`);\n }\n\n // MinIO\n if (config.minio) {\n services.push(` minio:\n image: minio/minio\n container_name: ${config.projectName}-minio\n restart: unless-stopped\n command: server /data --console-address \":9001\"\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data`);\n }\n\n // Extra services from installers\n services.push(...extraServices);\n\n // Volumes\n const volumes: string[] = [];\n if (config.database === 'postgresql') volumes.push(' postgres_data:');\n if (config.database === 'mysql') volumes.push(' mysql_data:');\n if (config.database === 'mongodb') volumes.push(' mongodb_data:');\n if (config.redis) volumes.push(' redis_data:');\n if (config.queue === 'rabbitmq') volumes.push(' rabbitmq_data:');\n if (config.minio) volumes.push(' minio_data:');\n\n const content = `services:\n${services.join('\\n\\n')}\n\nvolumes:\n${volumes.join('\\n')}\n`;\n\n await writeFile(path.join(projectDir, 'docker-compose.yml'), content);\n}\n","import path from 'path';\nimport type { ProjectConfig, EnvEntry } from '../types/config.js';\nimport { writeFile } from '../helpers/filesystem.js';\n\nexport async function generateEnv(\n config: ProjectConfig,\n apiDir: string,\n envEntries: EnvEntry[]\n): Promise<void> {\n // Add base entries\n const baseEntries: EnvEntry[] = [\n { key: 'NODE_ENV', value: 'development', category: 'App', comment: 'Ambiente' },\n { key: 'PORT', value: '3001', category: 'App' },\n ];\n\n // Database entries\n if (config.database === 'postgresql') {\n baseEntries.push({\n key: 'DATABASE_URL',\n value: `postgresql://postgres:postgres@localhost:5432/${config.projectName.replace(/-/g, '_')}`,\n category: 'Database',\n });\n } else if (config.database === 'mysql') {\n baseEntries.push({\n key: 'DATABASE_URL',\n value: `mysql://user:password@localhost:3306/${config.projectName.replace(/-/g, '_')}`,\n category: 'Database',\n });\n } else if (config.database === 'mongodb') {\n baseEntries.push({\n key: 'MONGODB_URI',\n value: `mongodb://root:root@localhost:27017/${config.projectName.replace(/-/g, '_')}?authSource=admin`,\n category: 'Database',\n });\n }\n\n const allEntries = [...baseEntries, ...envEntries];\n\n // Group by category\n const categories = new Map<string, EnvEntry[]>();\n for (const entry of allEntries) {\n const cat = entry.category;\n if (!categories.has(cat)) categories.set(cat, []);\n categories.get(cat)!.push(entry);\n }\n\n // Build .env content\n const lines: string[] = [];\n for (const [category, entries] of categories) {\n lines.push(`# ${category}`);\n for (const entry of entries) {\n if (entry.comment) lines.push(`# ${entry.comment}`);\n lines.push(`${entry.key}=\"${entry.value}\"`);\n }\n lines.push('');\n }\n\n const envContent = lines.join('\\n');\n\n // Write .env and .env.example\n await writeFile(path.join(apiDir, '.env'), envContent);\n await writeFile(path.join(apiDir, '.env.example'), envContent);\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile } from '../helpers/filesystem.js';\nimport { getRunCommand } from '../helpers/runtime.js';\n\nexport async function generateReadme(config: ProjectConfig, projectDir: string): Promise<void> {\n const runCmd = getRunCommand(config.runtime);\n const hasDocker = config.database !== 'none' || config.redis || config.queue === 'rabbitmq' || config.minio;\n\n const authMethods = [\n config.auth.jwt && 'JWT',\n config.auth.magicLink && 'Magic Link',\n config.auth.googleOAuth && 'Google OAuth',\n ].filter(Boolean);\n\n const integrations = [\n config.integrations.viacep && 'ViaCEP',\n config.integrations.whatsapp && 'WhatsApp',\n config.integrations.stripe && 'Stripe',\n config.integrations.mercadoPago && 'Mercado Pago',\n config.integrations.abacatePay && 'AbacatePay',\n ].filter(Boolean);\n\n const infra = [\n config.redis && 'Redis',\n config.smtp && 'SMTP',\n config.minio && 'MinIO',\n config.pm2 && 'PM2',\n ].filter(Boolean);\n\n let content = `# ${config.projectName}\n\n${config.projectDescription}\n\n> Projeto gerado com [PlazerCLI](https://github.com/pablocarss/plazercli) + Liz AI Agent\n\n## Stack\n\n| Camada | Tecnologia |\n|--------|-----------|\n| Frontend | ${config.frontend} |\n| Backend | ${config.backend} |\n${config.database !== 'none' ? `| Banco de dados | ${config.database} ${config.usePrisma ? '(Prisma)' : '(Mongoose)'} |` : ''}\n${authMethods.length > 0 ? `| Autenticacao | ${authMethods.join(', ')} |` : ''}\n${config.queue !== 'none' ? `| Filas | ${config.queue} |` : ''}\n${infra.length > 0 ? `| Infraestrutura | ${infra.join(', ')} |` : ''}\n${integrations.length > 0 ? `| Integracoes | ${integrations.join(', ')} |` : ''}\n| Runtime | ${config.runtime} |\n\n## Estrutura\n\n\\`\\`\\`\n${config.projectName}/\n├── apps/\n│ ├── api/ # Backend ${config.backend}\n│ │ ├── src/\n${config.usePrisma ? '│ │ │ ├── database/ # Prisma service\\n' : ''}${config.useMongoose ? '│ │ │ ├── database/ # Mongoose models\\n' : ''}${config.hasAnyAuth ? '│ │ │ ├── auth/ # Autenticacao\\n' : ''}${config.redis || config.smtp || config.minio ? '│ │ │ ├── infra/ # Redis, Email, Storage\\n' : ''}${config.hasAnyQueue ? '│ │ │ ├── queue/ # Workers e jobs\\n' : ''}${config.hasAnyIntegration ? '│ │ │ ├── integrations/ # APIs externas\\n' : ''}${config.multiTenant ? '│ │ │ ├── tenant/ # Multi-tenant\\n' : ''}│ │ │ ├── routes/\n│ │ │ └── config/\n${config.usePrisma ? '│ │ └── prisma/schema.prisma\\n' : ''}│ │ └── .env\n│ └── web/ # Frontend ${config.frontend}\n│ └── src/\n├── docker-compose.yml\n├── CLAUDE.md # Liz config (Claude Code)\n├── AGENTS.md # Liz config (geral)\n└── README.md\n\\`\\`\\`\n\n## Quick Start\n\n\\`\\`\\`bash\n# Pre-requisitos: Node.js >= 20, ${config.runtime}${hasDocker ? ', Docker' : ''}\n`;\n\n let step = 1;\n\n if (hasDocker) {\n content += `\n# ${step}. Subir infraestrutura\ndocker compose up -d\n`;\n step++;\n }\n\n if (config.usePrisma) {\n content += `\n# ${step}. Criar tabelas no banco\ncd apps/api && npx prisma db push && cd ../..\n`;\n step++;\n }\n\n content += `\n# ${step}. Iniciar em modo desenvolvimento\n${runCmd} dev\n\\`\\`\\`\n\nPronto! Frontend em **http://localhost:3000** e API em **http://localhost:3001**\n`;\n\n // Auth endpoints documentation\n if (config.hasAnyAuth) {\n content += `\n## Autenticacao\n\n### Endpoints\n`;\n if (config.auth.jwt) {\n content += `\n**JWT:**\n- \\`POST /api/auth/register\\` - Criar conta\n \\`\\`\\`json\n { \"email\": \"user@email.com\", \"password\": \"123456\", \"name\": \"Nome\" }\n \\`\\`\\`\n- \\`POST /api/auth/login\\` - Login (retorna access_token)\n \\`\\`\\`json\n { \"email\": \"user@email.com\", \"password\": \"123456\" }\n \\`\\`\\`\n- Header: \\`Authorization: Bearer <token>\\`\n`;\n }\n if (config.auth.magicLink) {\n content += `\n**Magic Link:**\n- \\`POST /api/auth/magic-link/send\\` - Enviar link por email\n \\`\\`\\`json\n { \"email\": \"user@email.com\" }\n \\`\\`\\`\n- \\`GET /api/auth/magic-link/verify?token=xxx\\` - Verificar token\n`;\n }\n if (config.auth.googleOAuth) {\n content += `\n**Google OAuth:**\n- \\`GET /api/auth/google\\` - Redireciona para login Google\n- \\`GET /api/auth/google/callback\\` - Callback (configurar no Google Console)\n`;\n }\n }\n\n // Integrations documentation\n if (config.hasAnyIntegration) {\n content += `\n## Integracoes\n`;\n if (config.integrations.viacep) {\n content += `\n### ViaCEP\nServico em \\`apps/api/src/integrations/viacep/\\`\n\\`\\`\\`typescript\nimport { fetchAddress } from './integrations/viacep/viacep.service';\nconst endereco = await fetchAddress('01001000');\n\\`\\`\\`\n`;\n }\n if (config.integrations.stripe) {\n content += `\n### Stripe\nConfigurar \\`STRIPE_SECRET_KEY\\` e \\`STRIPE_WEBHOOK_SECRET\\` no .env\n\\`\\`\\`typescript\nimport { createCheckoutSession } from './integrations/stripe/stripe.service';\n\\`\\`\\`\n`;\n }\n if (config.integrations.mercadoPago) {\n content += `\n### Mercado Pago\nConfigurar \\`MERCADOPAGO_ACCESS_TOKEN\\` no .env\n\\`\\`\\`typescript\nimport { createPreference } from './integrations/mercado-pago/mercado-pago.service';\n\\`\\`\\`\n`;\n }\n if (config.integrations.whatsapp) {\n content += `\n### WhatsApp\nConfigurar \\`WHATSAPP_API_TOKEN\\` e \\`WHATSAPP_PHONE_ID\\` no .env\n\\`\\`\\`typescript\nimport { sendMessage } from './integrations/whatsapp/whatsapp.service';\nawait sendMessage('5511999999999', 'Olá!');\n\\`\\`\\`\n`;\n }\n }\n\n // Environment variables\n content += `\n## Variaveis de Ambiente\n\nEdite \\`apps/api/.env\\` com suas credenciais:\n\n| Variavel | Descricao |\n|----------|----------|\n| \\`PORT\\` | Porta da API (default: 3001) |\n`;\n\n if (config.database === 'postgresql' || config.database === 'mysql') {\n content += `| \\`DATABASE_URL\\` | URL de conexao do banco |\n`;\n }\n if (config.database === 'mongodb') {\n content += `| \\`MONGODB_URI\\` | URL de conexao do MongoDB |\n`;\n }\n if (config.auth.jwt) {\n content += `| \\`JWT_SECRET\\` | **Alterar em producao!** Secret para tokens |\n`;\n }\n if (config.auth.googleOAuth) {\n content += `| \\`GOOGLE_CLIENT_ID\\` | ID do app no Google Console |\n| \\`GOOGLE_CLIENT_SECRET\\` | Secret do app no Google Console |\n`;\n }\n if (config.redis) {\n content += `| \\`REDIS_HOST\\` | Host do Redis (default: localhost) |\n`;\n }\n if (config.smtp) {\n content += `| \\`SMTP_HOST\\`, \\`SMTP_USER\\`, \\`SMTP_PASS\\` | Credenciais SMTP |\n`;\n }\n if (config.minio) {\n content += `| \\`MINIO_ACCESS_KEY\\`, \\`MINIO_SECRET_KEY\\` | Credenciais MinIO |\n`;\n }\n if (config.integrations.stripe) {\n content += `| \\`STRIPE_SECRET_KEY\\` | Chave secreta do Stripe |\n`;\n }\n if (config.integrations.mercadoPago) {\n content += `| \\`MERCADOPAGO_ACCESS_TOKEN\\` | Token do Mercado Pago |\n`;\n }\n\n content += `\n## Scripts\n\n| Comando | Descricao |\n|---------|----------|\n| \\`${runCmd} dev\\` | Inicia todos os apps |\n| \\`${runCmd} build\\` | Build de producao |\n| \\`${runCmd} dev:api\\` | Inicia apenas a API |\n| \\`${runCmd} dev:web\\` | Inicia apenas o frontend |\n${config.usePrisma ? `| \\`cd apps/api && npx prisma studio\\` | Admin visual do banco |\\n| \\`cd apps/api && npx prisma db push\\` | Sync schema com banco |` : ''}\n${config.pm2 ? `| \\`pm2 start ecosystem.config.cjs\\` | Deploy com zero-downtime |` : ''}\n${hasDocker ? `| \\`docker compose up -d\\` | Subir infraestrutura |` : ''}\n\n## Liz - AI Agent\n\nEste projeto vem com a **Liz**, uma assistente de IA configurada para conhecer a arquitetura do projeto.\n\n- **Claude Code:** Liz carrega automaticamente via \\`CLAUDE.md\\`\n- **Cursor:** Regras em \\`.cursor/rules/liz.mdc\\`\n- **Outros:** Consulte \\`AGENTS.md\\` para contexto completo\n\n---\n\nGerado com [PlazerCLI](https://github.com/pablocarss/plazercli)\n`;\n\n await writeFile(path.join(projectDir, 'README.md'), content);\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile } from '../helpers/filesystem.js';\n\nexport async function generateWiring(config: ProjectConfig, apiDir: string): Promise<void> {\n switch (config.backend) {\n case 'nestjs':\n await wireNestjs(config, apiDir);\n break;\n case 'express':\n await wireExpress(config, apiDir);\n break;\n case 'fastify':\n await wireFastify(config, apiDir);\n break;\n }\n}\n\nasync function wireNestjs(config: ProjectConfig, apiDir: string): Promise<void> {\n const imports: string[] = [];\n const modules: string[] = [];\n\n imports.push(`import { Module } from '@nestjs/common';`);\n imports.push(`import { ConfigModule } from '@nestjs/config';`);\n imports.push(`import { AppController } from './app.controller';`);\n imports.push(`import { AppService } from './app.service';`);\n\n modules.push(`ConfigModule.forRoot({ isGlobal: true })`);\n\n if (config.usePrisma) {\n imports.push(`import { PrismaModule } from './database/prisma.module';`);\n modules.push('PrismaModule');\n }\n\n if (config.redis) {\n imports.push(`import { RedisModule } from './infra/redis/redis.module';`);\n modules.push('RedisModule');\n }\n\n if (config.smtp) {\n imports.push(`import { EmailModule } from './infra/email/email.module';`);\n modules.push('EmailModule');\n }\n\n if (config.minio) {\n imports.push(`import { StorageModule } from './infra/storage/storage.module';`);\n modules.push('StorageModule');\n }\n\n if (config.auth.jwt) {\n imports.push(`import { AuthModule } from './auth/auth.module';`);\n modules.push('AuthModule');\n }\n\n if (config.multiTenant) {\n imports.push(`import { TenantModule } from './tenant/tenant.module';`);\n modules.push('TenantModule');\n }\n\n if (config.queue === 'bullmq') {\n imports.push(`import { QueueModule } from './queue/queue.module';`);\n modules.push('QueueModule');\n }\n\n if (config.queue === 'rabbitmq') {\n imports.push(`import { RabbitMQModule } from './queue/rabbitmq.config';`);\n modules.push('RabbitMQModule');\n }\n\n const content = `${imports.join('\\n')}\n\n@Module({\n imports: [\n ${modules.join(',\\n ')},\n ],\n controllers: [AppController],\n providers: [AppService],\n})\nexport class AppModule {}\n`;\n\n await writeFile(path.join(apiDir, 'src', 'app.module.ts'), content);\n}\n\nasync function wireExpress(config: ProjectConfig, apiDir: string): Promise<void> {\n const imports: string[] = [];\n const setupLines: string[] = [];\n const routeLines: string[] = [];\n\n imports.push(`import express from 'express';`);\n imports.push(`import cors from 'cors';`);\n imports.push(`import helmet from 'helmet';`);\n imports.push(`import { config } from './config/index.js';`);\n imports.push(`import { router } from './routes/index.js';`);\n imports.push(`import { errorHandler } from './middlewares/errorHandler.js';`);\n\n if (config.useMongoose) {\n imports.push(`import { connectDB } from './database/connection.js';`);\n setupLines.push(` // Conectar ao MongoDB`);\n setupLines.push(` await connectDB();`);\n }\n\n if (config.multiTenant) {\n imports.push(`import { tenantMiddleware } from './tenant/tenant.middleware.js';`);\n }\n\n if (config.auth.jwt) {\n imports.push(`import { authRouter } from './auth/auth.routes.js';`);\n }\n\n if (config.auth.magicLink) {\n imports.push(`import { magicLinkRouter } from './auth/magic-link.routes.js';`);\n }\n\n if (config.auth.googleOAuth) {\n imports.push(`import { googleRouter } from './auth/google.routes.js';`);\n }\n\n if (config.queue === 'rabbitmq') {\n imports.push(`import { connectRabbitMQ } from './queue/rabbitmq.js';`);\n setupLines.push(` // Conectar ao RabbitMQ`);\n setupLines.push(` await connectRabbitMQ();`);\n }\n\n if (config.minio) {\n imports.push(`import { initStorage } from './infra/storage/storage.js';`);\n setupLines.push(` // Inicializar MinIO storage`);\n setupLines.push(` await initStorage();`);\n }\n\n // Build middleware registration\n if (config.multiTenant) {\n routeLines.push(`app.use(tenantMiddleware);`);\n }\n if (config.auth.jwt) {\n routeLines.push(`app.use('/api/auth', authRouter);`);\n }\n if (config.auth.magicLink) {\n routeLines.push(`app.use('/api/auth/magic-link', magicLinkRouter);`);\n }\n if (config.auth.googleOAuth) {\n routeLines.push(`app.use('/api/auth/google', googleRouter);`);\n }\n\n const appContent = `${imports.join('\\n')}\n\nconst app = express();\n\napp.use(helmet());\napp.use(cors({ origin: config.corsOrigin }));\napp.use(express.json());\n\n${routeLines.length > 0 ? '// Rotas auto-configuradas\\n' + routeLines.join('\\n') + '\\n' : ''}\napp.use('/api', router);\n\napp.use(errorHandler);\n\nexport { app };\n`;\n\n // Also rewrite index.ts with setup\n const indexContent = `import { app } from './app.js';\nimport { config } from './config/index.js';\n\nasync function start() {\n${setupLines.length > 0 ? setupLines.join('\\n') + '\\n' : ''}\n app.listen(config.port, () => {\n console.log(\\`🚀 API rodando em http://localhost:\\${config.port}\\`);\n });\n}\n\nstart().catch((err) => {\n console.error('Erro ao iniciar:', err);\n process.exit(1);\n});\n`;\n\n await writeFile(path.join(apiDir, 'src', 'app.ts'), appContent);\n await writeFile(path.join(apiDir, 'src', 'index.ts'), indexContent);\n}\n\nasync function wireFastify(config: ProjectConfig, apiDir: string): Promise<void> {\n const imports: string[] = [];\n const pluginLines: string[] = [];\n const setupLines: string[] = [];\n\n imports.push(`import Fastify from 'fastify';`);\n imports.push(`import cors from '@fastify/cors';`);\n imports.push(`import helmet from '@fastify/helmet';`);\n imports.push(`import { config } from './config/index.js';`);\n imports.push(`import { registerRoutes } from './routes/index.js';`);\n\n if (config.useMongoose) {\n imports.push(`import { connectDB } from './database/connection.js';`);\n setupLines.push(` await connectDB();`);\n }\n\n if (config.multiTenant) {\n imports.push(`import tenantPlugin from './tenant/tenant.plugin.js';`);\n pluginLines.push(` await app.register(tenantPlugin);`);\n }\n\n if (config.auth.jwt) {\n imports.push(`import { authRoutes } from './auth/auth.routes.js';`);\n pluginLines.push(` await app.register(authRoutes);`);\n }\n\n if (config.auth.magicLink) {\n imports.push(`import { magicLinkRoutes } from './auth/magic-link.routes.js';`);\n pluginLines.push(` await app.register(magicLinkRoutes);`);\n }\n\n if (config.auth.googleOAuth) {\n imports.push(`import { googleAuthRoutes } from './auth/google.routes.js';`);\n pluginLines.push(` await app.register(googleAuthRoutes);`);\n }\n\n if (config.queue === 'rabbitmq') {\n imports.push(`import { connectRabbitMQ } from './queue/rabbitmq.js';`);\n setupLines.push(` await connectRabbitMQ();`);\n }\n\n if (config.minio) {\n imports.push(`import { initStorage } from './infra/storage/storage.js';`);\n setupLines.push(` await initStorage();`);\n }\n\n const appContent = `${imports.join('\\n')}\n\nexport async function buildApp() {\n const app = Fastify({\n logger: config.nodeEnv === 'development',\n });\n\n await app.register(helmet);\n await app.register(cors, { origin: config.corsOrigin });\n\n${pluginLines.length > 0 ? ' // Plugins auto-configurados\\n' + pluginLines.join('\\n') + '\\n' : ''}\n registerRoutes(app);\n\n return app;\n}\n`;\n\n const indexContent = `import { buildApp } from './app.js';\nimport { config } from './config/index.js';\n\nasync function start() {\n${setupLines.length > 0 ? setupLines.join('\\n') + '\\n' : ''}\n const app = await buildApp();\n\n await app.listen({ port: config.port, host: config.host });\n console.log(\\`🚀 API rodando em http://localhost:\\${config.port}\\`);\n}\n\nstart().catch((err) => {\n console.error('Erro ao iniciar:', err);\n process.exit(1);\n});\n`;\n\n await writeFile(path.join(apiDir, 'src', 'app.ts'), appContent);\n await writeFile(path.join(apiDir, 'src', 'index.ts'), indexContent);\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile, ensureDir } from '../helpers/filesystem.js';\n\nexport async function generateLiz(config: ProjectConfig, projectDir: string): Promise<void> {\n // Generate AGENTS.md (Claude Code / Copilot identity)\n await generateAgentsMd(config, projectDir);\n\n // Generate .cursor/rules (Cursor AI rules)\n await generateCursorRules(config, projectDir);\n\n // Generate CLAUDE.md (Claude Code specific)\n await generateClaudeMd(config, projectDir);\n}\n\nasync function generateAgentsMd(config: ProjectConfig, projectDir: string): Promise<void> {\n const authMethods = [\n config.auth.jwt && 'JWT',\n config.auth.magicLink && 'Magic Link',\n config.auth.googleOAuth && 'Google OAuth',\n ].filter(Boolean);\n\n const integrations = [\n config.integrations.viacep && 'ViaCEP',\n config.integrations.whatsapp && 'WhatsApp',\n config.integrations.stripe && 'Stripe',\n config.integrations.mercadoPago && 'Mercado Pago',\n config.integrations.abacatePay && 'AbacatePay',\n ].filter(Boolean);\n\n const content = `# Liz - AI Development Agent\n\n## Identidade\n\nEu sou a **Liz**, a assistente de desenvolvimento do projeto **${config.projectName}**. Fui configurada pelo PlazerCLI para conhecer profundamente a arquitetura deste projeto e ajudar no desenvolvimento.\n\n## Stack do Projeto\n\n- **Estrutura:** Monorepo com workspaces\n- **Frontend:** ${config.frontend} (apps/web/)\n- **Backend:** ${config.backend} (apps/api/)\n- **Runtime:** ${config.runtime}\n${config.database !== 'none' ? `- **Banco de dados:** ${config.database} ${config.usePrisma ? '(Prisma ORM)' : '(Mongoose ODM)'}` : ''}\n${authMethods.length > 0 ? `- **Autenticação:** ${authMethods.join(', ')}` : ''}\n${config.redis ? '- **Cache:** Redis (ioredis)' : ''}\n${config.queue !== 'none' ? `- **Filas:** ${config.queue}` : ''}\n${config.smtp ? '- **Email:** Nodemailer (SMTP)' : ''}\n${config.minio ? '- **Storage:** MinIO (S3-compatible)' : ''}\n${config.multiTenant ? '- **Multi-tenant:** Sim (isolamento por header/subdomain)' : ''}\n${config.pm2 ? '- **Deploy:** PM2 (cluster mode, zero-downtime)' : ''}\n${integrations.length > 0 ? `- **Integrações:** ${integrations.join(', ')}` : ''}\n\n## Estrutura de Diretórios\n\n\\`\\`\\`\n${config.projectName}/\n├── apps/\n│ ├── api/ # Backend (${config.backend})\n│ │ ├── src/\n${config.usePrisma ? '│ │ │ ├── database/ # Prisma service e conexão\\n' : ''}${config.useMongoose ? '│ │ │ ├── database/ # Mongoose models e conexão\\n' : ''}${config.hasAnyAuth ? '│ │ │ ├── auth/ # Autenticação e guards\\n' : ''}${config.redis ? '│ │ │ ├── infra/redis/ # Redis service\\n' : ''}${config.smtp ? '│ │ │ ├── infra/email/ # Email service e templates\\n' : ''}${config.minio ? '│ │ │ ├── infra/storage/ # MinIO storage service\\n' : ''}${config.hasAnyQueue ? '│ │ │ ├── queue/ # Workers e processadores\\n' : ''}${config.hasAnyIntegration ? '│ │ │ ├── integrations/ # Integrações externas\\n' : ''}${config.multiTenant ? '│ │ │ ├── tenant/ # Multi-tenant middleware\\n' : ''}│ │ │ ├── routes/ # Rotas da API\n│ │ │ ├── config/ # Configurações\n│ │ │ └── middlewares/ # Middlewares\n${config.usePrisma ? '│ │ └── prisma/ # Schema do banco\\n' : ''}│ │ └── .env # Variáveis de ambiente\n│ └── web/ # Frontend (${config.frontend})\n│ └── src/\n├── docker-compose.yml\n├── .env.example\n└── README.md\n\\`\\`\\`\n\n## Convenções\n\n### Código\n- TypeScript strict mode\n- ESM modules (import/export)\n- Async/await para operações assíncronas\n- Nomes em inglês para código, comentários podem ser em português\n\n### API\n- Prefixo \\`/api\\` em todas as rotas\n- Health check em \\`GET /api/health\\`\n${config.hasAnyAuth ? `- Rotas de auth em \\`/api/auth/*\\`` : ''}\n- Respostas JSON com status HTTP corretos\n\n### Banco de Dados\n${config.usePrisma ? `- Prisma como ORM\n- Schema em \\`apps/api/prisma/schema.prisma\\`\n- Rodar \\`npx prisma db push\\` após alterar schema\n- Rodar \\`npx prisma generate\\` após alterar models` : ''}\n${config.useMongoose ? `- Mongoose como ODM\n- Models em \\`apps/api/src/database/models/\\`\n- Conexão em \\`apps/api/src/database/connection.ts\\`` : ''}\n\n## Como me usar\n\nAo desenvolver, me peça para:\n- Criar novas features seguindo a arquitetura existente\n- Criar novos endpoints/rotas\n- Adicionar models ao banco de dados\n- Criar novos workers/jobs\n- Integrar novos serviços\n- Debugar erros com contexto do projeto\n- Escrever testes\n\nEu conheço toda a stack e vou seguir as convenções do projeto.\n\n---\n*Configurada por PlazerCLI - https://github.com/pablocarss/plazercli*\n`;\n\n await writeFile(path.join(projectDir, 'AGENTS.md'), content);\n}\n\nasync function generateCursorRules(config: ProjectConfig, projectDir: string): Promise<void> {\n await ensureDir(path.join(projectDir, '.cursor', 'rules'));\n\n const content = `# Liz - PlazerCLI AI Agent Rules\n\nYou are Liz, the AI development assistant for the \"${config.projectName}\" project.\n\n## Project Context\n- Monorepo with apps/api (${config.backend}) and apps/web (${config.frontend})\n- Runtime: ${config.runtime}\n${config.database !== 'none' ? `- Database: ${config.database} ${config.usePrisma ? 'with Prisma ORM' : 'with Mongoose ODM'}` : ''}\n${config.hasAnyAuth ? '- Authentication configured and wired' : ''}\n${config.redis ? '- Redis for caching' : ''}\n${config.queue !== 'none' ? `- Queue system: ${config.queue}` : ''}\n\n## Rules\n- Always use TypeScript with strict mode\n- Follow existing patterns in the codebase\n- Use ESM imports (import/export, .js extensions)\n- API routes must be prefixed with /api\n- Use the existing database service/ORM for all DB operations\n${config.usePrisma ? '- After schema changes, remind to run: npx prisma db push' : ''}\n${config.backend === 'nestjs' ? '- Follow NestJS patterns: modules, controllers, services, guards' : ''}\n${config.backend === 'express' ? '- Use Express Router for new route groups' : ''}\n${config.backend === 'fastify' ? '- Use Fastify plugins for new functionality' : ''}\n- Write clean, minimal code - no over-engineering\n- Handle errors properly with appropriate HTTP status codes\n`;\n\n await writeFile(path.join(projectDir, '.cursor', 'rules', 'liz.mdc'), content);\n}\n\nasync function generateClaudeMd(config: ProjectConfig, projectDir: string): Promise<void> {\n const content = `# CLAUDE.md - Liz Agent Configuration\n\nYou are **Liz**, the AI development assistant for **${config.projectName}**.\n\n## Project Overview\nThis is a fullstack monorepo generated by PlazerCLI.\n\n- \\`apps/api/\\` - Backend (${config.backend})\n- \\`apps/web/\\` - Frontend (${config.frontend})\n- Runtime: ${config.runtime}\n${config.database !== 'none' ? `- Database: ${config.database}` : ''}\n\n## Key Files\n${config.backend === 'nestjs' ? '- `apps/api/src/app.module.ts` - Main module (all features auto-imported)' : ''}\n${config.backend === 'express' ? '- `apps/api/src/app.ts` - Express app (all routes auto-registered)' : ''}\n${config.backend === 'fastify' ? '- `apps/api/src/app.ts` - Fastify app (all plugins auto-registered)' : ''}\n${config.usePrisma ? '- `apps/api/prisma/schema.prisma` - Database schema' : ''}\n- \\`apps/api/.env\\` - Environment variables\n- \\`docker-compose.yml\\` - Infrastructure services\n\n## Commands\n- \\`${config.runtime} run dev\\` - Start all apps\n- \\`${config.runtime} run dev:api\\` - Start only API\n- \\`${config.runtime} run dev:web\\` - Start only frontend\n${config.usePrisma ? '- `cd apps/api && npx prisma db push` - Push schema to DB\\n- `cd apps/api && npx prisma studio` - Open DB admin' : ''}\n- \\`docker compose up -d\\` - Start infrastructure\n\n## Conventions\n- TypeScript strict, ESM modules\n- API prefix: /api\n- Follow existing patterns when creating new features\n`;\n\n await writeFile(path.join(projectDir, 'CLAUDE.md'), content);\n}\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const prismaInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, devDependencies, scripts } = opts;\n const provider = config.database === 'postgresql' ? 'postgresql' : 'mysql';\n const dbName = config.projectName.replace(/-/g, '_');\n\n await ensureDir(path.join(apiDir, 'prisma'));\n await ensureDir(path.join(apiDir, 'src', 'database'));\n\n // Schema\n let schema = `generator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"${provider}\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel User {\n id String @id @default(cuid())\n email String @unique\n name String?\n password String?\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n`;\n\n if (config.multiTenant) {\n schema += ` tenantId String @map(\"tenant_id\")\n tenant Tenant @relation(fields: [tenantId], references: [id])\n`;\n }\n\n schema += `\n @@map(\"users\")\n}\n`;\n\n if (config.multiTenant) {\n schema += `\nmodel Tenant {\n id String @id @default(cuid())\n name String\n slug String @unique\n users User[]\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n @@map(\"tenants\")\n}\n`;\n }\n\n await writeFile(path.join(apiDir, 'prisma', 'schema.prisma'), schema);\n\n // Prisma service\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'database', 'prisma.service.ts'), `import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';\nimport { PrismaClient } from '@prisma/client';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {\n async onModuleInit() {\n await this.$connect();\n }\n\n async onModuleDestroy() {\n await this.$disconnect();\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'database', 'prisma.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { PrismaService } from './prisma.service';\n\n@Global()\n@Module({\n providers: [PrismaService],\n exports: [PrismaService],\n})\nexport class PrismaModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'database', 'prisma.ts'), `import { PrismaClient } from '@prisma/client';\n\nconst globalForPrisma = globalThis as unknown as { prisma: PrismaClient };\n\nexport const prisma = globalForPrisma.prisma || new PrismaClient();\n\nif (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;\n\nexport default prisma;\n`);\n }\n\n // Dependencies\n dependencies['@prisma/client'] = deps['@prisma/client'];\n devDependencies['prisma'] = deps.prisma;\n\n // Scripts\n scripts['db:push'] = 'prisma db push';\n scripts['db:migrate'] = 'prisma migrate dev';\n scripts['db:studio'] = 'prisma studio';\n scripts['db:seed'] = 'prisma db seed';\n scripts['db:generate'] = 'prisma generate';\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const mongooseInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'database'));\n await ensureDir(path.join(apiDir, 'src', 'database', 'models'));\n\n // Connection\n if (config.multiTenant) {\n await writeFile(path.join(apiDir, 'src', 'database', 'connection.ts'), `import mongoose from 'mongoose';\n\nconst connections = new Map<string, mongoose.Connection>();\n\nexport async function connectDB(): Promise<mongoose.Connection> {\n const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/${config.projectName.replace(/-/g, '_')}';\n const conn = await mongoose.connect(uri);\n console.log('MongoDB conectado');\n return conn.connection;\n}\n\nexport function getTenantConnection(tenantId: string): mongoose.Connection {\n if (connections.has(tenantId)) {\n return connections.get(tenantId)!;\n }\n\n const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017';\n const conn = mongoose.createConnection(\\`\\${uri}/tenant_\\${tenantId}\\`);\n connections.set(tenantId, conn);\n return conn;\n}\n\nexport default { connectDB, getTenantConnection };\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'database', 'connection.ts'), `import mongoose from 'mongoose';\n\nexport async function connectDB(): Promise<void> {\n const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/${config.projectName.replace(/-/g, '_')}';\n await mongoose.connect(uri);\n console.log('MongoDB conectado');\n}\n\nexport default { connectDB };\n`);\n }\n\n // User model\n await writeFile(path.join(apiDir, 'src', 'database', 'models', 'user.model.ts'), `import mongoose, { Schema, Document } from 'mongoose';\n\nexport interface IUser extends Document {\n email: string;\n name?: string;\n password?: string;\n${config.multiTenant ? ' tenantId: string;\\n' : ''} createdAt: Date;\n updatedAt: Date;\n}\n\nconst UserSchema = new Schema<IUser>(\n {\n email: { type: String, required: true, unique: true },\n name: { type: String },\n password: { type: String },\n${config.multiTenant ? \" tenantId: { type: String, required: true, index: true },\\n\" : ''} },\n { timestamps: true }\n);\n\nexport const User = mongoose.model<IUser>('User', UserSchema);\n`);\n\n dependencies['mongoose'] = deps.mongoose;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const jwtInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'auth'));\n\n envEntries.push(\n { key: 'JWT_SECRET', value: 'change-me-in-production-use-a-strong-secret', category: 'Authentication' },\n { key: 'JWT_EXPIRES_IN', value: '7d', category: 'Authentication' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'jwt.strategy.ts'), `import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n constructor(configService: ConfigService) {\n super({\n jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n ignoreExpiration: false,\n secretOrKey: configService.get<string>('JWT_SECRET'),\n });\n }\n\n async validate(payload: { sub: string; email: string }) {\n return { id: payload.sub, email: payload.email };\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.module.ts'), `import { Module } from '@nestjs/common';\nimport { JwtModule } from '@nestjs/jwt';\nimport { PassportModule } from '@nestjs/passport';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { JwtStrategy } from './jwt.strategy';\n\n@Module({\n imports: [\n PassportModule,\n JwtModule.registerAsync({\n imports: [ConfigModule],\n useFactory: (configService: ConfigService) => ({\n secret: configService.get<string>('JWT_SECRET'),\n signOptions: { expiresIn: configService.get<string>('JWT_EXPIRES_IN', '7d') },\n }),\n inject: [ConfigService],\n }),\n ],\n controllers: [AuthController],\n providers: [AuthService, JwtStrategy],\n exports: [AuthService],\n})\nexport class AuthModule {}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.service.ts'), `import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { JwtService } from '@nestjs/jwt';\nimport * as bcrypt from 'bcryptjs';\n\n@Injectable()\nexport class AuthService {\n constructor(private jwtService: JwtService) {}\n\n async hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, 10);\n }\n\n async comparePassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash);\n }\n\n async generateToken(payload: { sub: string; email: string }): Promise<string> {\n return this.jwtService.sign(payload);\n }\n\n async validateToken(token: string) {\n try {\n return this.jwtService.verify(token);\n } catch {\n throw new UnauthorizedException('Token inválido');\n }\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.controller.ts'), `import { Controller, Post, Body } from '@nestjs/common';\nimport { AuthService } from './auth.service';\n\n@Controller('auth')\nexport class AuthController {\n constructor(private readonly authService: AuthService) {}\n\n @Post('login')\n async login(@Body() body: { email: string; password: string }) {\n // TODO: Buscar usuario no banco e validar password\n const token = await this.authService.generateToken({\n sub: 'user-id',\n email: body.email,\n });\n return { access_token: token };\n }\n\n @Post('register')\n async register(@Body() body: { email: string; password: string; name?: string }) {\n const hashedPassword = await this.authService.hashPassword(body.password);\n // TODO: Criar usuario no banco com hashedPassword\n const token = await this.authService.generateToken({\n sub: 'new-user-id',\n email: body.email,\n });\n return { access_token: token };\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'jwt-auth.guard.ts'), `import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n`);\n\n dependencies['@nestjs/jwt'] = deps['@nestjs/jwt'];\n dependencies['@nestjs/passport'] = deps['@nestjs/passport'];\n dependencies['passport'] = deps.passport;\n dependencies['passport-jwt'] = deps['passport-jwt'];\n devDependencies['@types/passport-jwt'] = deps['@types/passport-jwt'];\n } else {\n // Express / Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'jwt.ts'), `import jwt from 'jsonwebtoken';\n\nconst JWT_SECRET = process.env.JWT_SECRET || 'change-me';\nconst JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '7d';\n\nexport function generateToken(payload: { sub: string; email: string }): string {\n return jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });\n}\n\nexport function verifyToken(token: string) {\n return jwt.verify(token, JWT_SECRET);\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'hash.ts'), `import bcrypt from 'bcryptjs';\n\nexport async function hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, 10);\n}\n\nexport async function comparePassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash);\n}\n`);\n\n if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.middleware.ts'), `import type { Request, Response, NextFunction } from 'express';\nimport { verifyToken } from './jwt.js';\n\nexport function authMiddleware(req: Request, res: Response, next: NextFunction) {\n const authHeader = req.headers.authorization;\n if (!authHeader?.startsWith('Bearer ')) {\n return res.status(401).json({ error: 'Token não fornecido' });\n }\n\n try {\n const token = authHeader.split(' ')[1];\n const payload = verifyToken(token);\n (req as any).user = payload;\n next();\n } catch {\n return res.status(401).json({ error: 'Token inválido' });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.routes.ts'), `import { Router } from 'express';\nimport { generateToken } from './jwt.js';\nimport { hashPassword, comparePassword } from './hash.js';\n\nconst authRouter = Router();\n\nauthRouter.post('/login', async (req, res) => {\n const { email, password } = req.body;\n // TODO: Buscar usuario no banco e validar password\n const token = generateToken({ sub: 'user-id', email });\n res.json({ access_token: token });\n});\n\nauthRouter.post('/register', async (req, res) => {\n const { email, password, name } = req.body;\n const hashedPassword = await hashPassword(password);\n // TODO: Criar usuario no banco com hashedPassword\n const token = generateToken({ sub: 'new-user-id', email });\n res.json({ access_token: token });\n});\n\nexport { authRouter };\n`);\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.hook.ts'), `import type { FastifyRequest, FastifyReply } from 'fastify';\nimport { verifyToken } from './jwt.js';\n\nexport async function authHook(request: FastifyRequest, reply: FastifyReply) {\n const authHeader = request.headers.authorization;\n if (!authHeader?.startsWith('Bearer ')) {\n return reply.status(401).send({ error: 'Token não fornecido' });\n }\n\n try {\n const token = authHeader.split(' ')[1];\n const payload = verifyToken(token);\n (request as any).user = payload;\n } catch {\n return reply.status(401).send({ error: 'Token inválido' });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.routes.ts'), `import type { FastifyInstance } from 'fastify';\nimport { generateToken } from './jwt.js';\nimport { hashPassword } from './hash.js';\n\nexport async function authRoutes(app: FastifyInstance) {\n app.post('/api/auth/login', async (request) => {\n const { email, password } = request.body as { email: string; password: string };\n // TODO: Buscar usuario no banco e validar password\n const token = generateToken({ sub: 'user-id', email });\n return { access_token: token };\n });\n\n app.post('/api/auth/register', async (request) => {\n const { email, password, name } = request.body as { email: string; password: string; name?: string };\n const hashedPassword = await hashPassword(password);\n // TODO: Criar usuario no banco com hashedPassword\n const token = generateToken({ sub: 'new-user-id', email });\n return { access_token: token };\n });\n}\n`);\n }\n\n dependencies['jsonwebtoken'] = deps.jsonwebtoken;\n devDependencies['@types/jsonwebtoken'] = deps['@types/jsonwebtoken'];\n }\n\n dependencies['bcryptjs'] = deps.bcryptjs;\n devDependencies['@types/bcryptjs'] = deps['@types/bcryptjs'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const magicLinkInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'auth'));\n\n envEntries.push(\n { key: 'MAGIC_LINK_EXPIRY_MINUTES', value: '15', category: 'Authentication' },\n { key: 'APP_URL', value: 'http://localhost:3000', category: 'Authentication', comment: 'URL do frontend para o magic link' },\n );\n\n const serviceContent = `import { nanoid } from 'nanoid';\n\ninterface MagicLinkToken {\n token: string;\n email: string;\n expiresAt: Date;\n}\n\n// Em producao, armazene no banco de dados ou Redis\nconst tokens = new Map<string, MagicLinkToken>();\n\nconst EXPIRY_MINUTES = Number(process.env.MAGIC_LINK_EXPIRY_MINUTES) || 15;\nconst APP_URL = process.env.APP_URL || 'http://localhost:3000';\n\nexport function generateMagicLink(email: string): { token: string; url: string } {\n const token = nanoid(32);\n const expiresAt = new Date(Date.now() + EXPIRY_MINUTES * 60 * 1000);\n\n tokens.set(token, { token, email, expiresAt });\n\n const url = \\`\\${APP_URL}/auth/verify?token=\\${token}\\`;\n return { token, url };\n}\n\nexport function verifyMagicLinkToken(token: string): { valid: boolean; email?: string } {\n const entry = tokens.get(token);\n if (!entry) return { valid: false };\n if (entry.expiresAt < new Date()) {\n tokens.delete(token);\n return { valid: false };\n }\n tokens.delete(token);\n return { valid: true, email: entry.email };\n}\n`;\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'magic-link.service.ts'), serviceContent);\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'magic-link.controller.ts'), `import { Controller, Post, Body, Get, Query, BadRequestException } from '@nestjs/common';\nimport { generateMagicLink, verifyMagicLinkToken } from './magic-link.service';\n\n@Controller('auth/magic-link')\nexport class MagicLinkController {\n @Post('send')\n async sendMagicLink(@Body() body: { email: string }) {\n const { url } = generateMagicLink(body.email);\n // TODO: Enviar email com o magic link usando o email service\n console.log('Magic link:', url);\n return { message: 'Magic link enviado para o email' };\n }\n\n @Get('verify')\n async verify(@Query('token') token: string) {\n const result = verifyMagicLinkToken(token);\n if (!result.valid) {\n throw new BadRequestException('Token inválido ou expirado');\n }\n // TODO: Criar sessao/JWT para o usuario\n return { message: 'Login realizado', email: result.email };\n }\n}\n`);\n } else if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'magic-link.routes.ts'), `import { Router } from 'express';\nimport { generateMagicLink, verifyMagicLinkToken } from './magic-link.service.js';\n\nconst magicLinkRouter = Router();\n\nmagicLinkRouter.post('/send', async (req, res) => {\n const { email } = req.body;\n const { url } = generateMagicLink(email);\n // TODO: Enviar email com o magic link usando o email service\n console.log('Magic link:', url);\n res.json({ message: 'Magic link enviado para o email' });\n});\n\nmagicLinkRouter.get('/verify', async (req, res) => {\n const token = req.query.token as string;\n const result = verifyMagicLinkToken(token);\n if (!result.valid) {\n return res.status(400).json({ error: 'Token inválido ou expirado' });\n }\n // TODO: Criar sessao/JWT para o usuario\n res.json({ message: 'Login realizado', email: result.email });\n});\n\nexport { magicLinkRouter };\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'auth', 'magic-link.routes.ts'), `import type { FastifyInstance } from 'fastify';\nimport { generateMagicLink, verifyMagicLinkToken } from './magic-link.service.js';\n\nexport async function magicLinkRoutes(app: FastifyInstance) {\n app.post('/api/auth/magic-link/send', async (request) => {\n const { email } = request.body as { email: string };\n const { url } = generateMagicLink(email);\n // TODO: Enviar email com o magic link usando o email service\n console.log('Magic link:', url);\n return { message: 'Magic link enviado para o email' };\n });\n\n app.get('/api/auth/magic-link/verify', async (request, reply) => {\n const { token } = request.query as { token: string };\n const result = verifyMagicLinkToken(token);\n if (!result.valid) {\n return reply.status(400).send({ error: 'Token inválido ou expirado' });\n }\n // TODO: Criar sessao/JWT para o usuario\n return { message: 'Login realizado', email: result.email };\n });\n}\n`);\n }\n\n dependencies['nanoid'] = deps.nanoid;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const googleOauthInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'auth'));\n\n envEntries.push(\n { key: 'GOOGLE_CLIENT_ID', value: '', category: 'Google OAuth', comment: 'Obtenha em https://console.cloud.google.com' },\n { key: 'GOOGLE_CLIENT_SECRET', value: '', category: 'Google OAuth' },\n { key: 'GOOGLE_CALLBACK_URL', value: 'http://localhost:3001/api/auth/google/callback', category: 'Google OAuth' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'google.strategy.ts'), `import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy, VerifyCallback, Profile } from 'passport-google-oauth20';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class GoogleStrategy extends PassportStrategy(Strategy, 'google') {\n constructor(configService: ConfigService) {\n super({\n clientID: configService.get<string>('GOOGLE_CLIENT_ID'),\n clientSecret: configService.get<string>('GOOGLE_CLIENT_SECRET'),\n callbackURL: configService.get<string>('GOOGLE_CALLBACK_URL'),\n scope: ['email', 'profile'],\n });\n }\n\n async validate(\n accessToken: string,\n refreshToken: string,\n profile: Profile,\n done: VerifyCallback,\n ) {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n googleId: profile.id,\n avatar: profile.photos?.[0]?.value,\n };\n done(null, user);\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'google.controller.ts'), `import { Controller, Get, Req, Res, UseGuards } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport type { Request, Response } from 'express';\n\n@Controller('auth/google')\nexport class GoogleController {\n @Get()\n @UseGuards(AuthGuard('google'))\n async googleAuth() {\n // Redireciona para o Google\n }\n\n @Get('callback')\n @UseGuards(AuthGuard('google'))\n async googleCallback(@Req() req: Request, @Res() res: Response) {\n const user = req.user;\n // TODO: Criar/buscar usuario no banco, gerar JWT\n console.log('Google user:', user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n}\n`);\n\n dependencies['@nestjs/passport'] = deps['@nestjs/passport'];\n dependencies['passport'] = deps.passport;\n } else if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'google.routes.ts'), `import { Router } from 'express';\nimport passport from 'passport';\nimport { Strategy as GoogleStrategy } from 'passport-google-oauth20';\n\npassport.use(\n new GoogleStrategy(\n {\n clientID: process.env.GOOGLE_CLIENT_ID || '',\n clientSecret: process.env.GOOGLE_CLIENT_SECRET || '',\n callbackURL: process.env.GOOGLE_CALLBACK_URL || 'http://localhost:3001/api/auth/google/callback',\n },\n async (accessToken, refreshToken, profile, done) => {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n googleId: profile.id,\n avatar: profile.photos?.[0]?.value,\n };\n // TODO: Criar/buscar usuario no banco\n done(null, user);\n }\n )\n);\n\nconst googleRouter = Router();\n\ngoogleRouter.get('/', passport.authenticate('google', { scope: ['profile', 'email'] }));\n\ngoogleRouter.get(\n '/callback',\n passport.authenticate('google', { session: false }),\n (req, res) => {\n // TODO: Gerar JWT e redirecionar\n console.log('Google user:', req.user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n);\n\nexport { googleRouter };\n`);\n\n dependencies['passport'] = deps.passport;\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'google.routes.ts'), `import type { FastifyInstance } from 'fastify';\n\n// Para Fastify, recomendamos usar @fastify/oauth2\n// npm install @fastify/oauth2\nexport async function googleAuthRoutes(app: FastifyInstance) {\n // TODO: Configurar @fastify/oauth2 para Google\n // Documentacao: https://github.com/fastify/fastify-oauth2\n\n app.get('/api/auth/google', async (request, reply) => {\n const clientId = process.env.GOOGLE_CLIENT_ID;\n const redirectUri = process.env.GOOGLE_CALLBACK_URL;\n const url = \\`https://accounts.google.com/o/oauth2/v2/auth?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&response_type=code&scope=email profile\\`;\n reply.redirect(url);\n });\n\n app.get('/api/auth/google/callback', async (request) => {\n const { code } = request.query as { code: string };\n // TODO: Trocar code por tokens, buscar perfil, criar/buscar usuario\n return { message: 'Google OAuth callback', code };\n });\n}\n`);\n }\n\n dependencies['passport-google-oauth20'] = deps['passport-google-oauth20'];\n devDependencies['@types/passport-google-oauth20'] = deps['@types/passport-google-oauth20'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const bullmqInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'queue'));\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'queue', 'queue.module.ts'), `import { Module } from '@nestjs/common';\nimport { BullModule } from '@nestjs/bullmq';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { ExampleProcessor } from './example.processor';\n\n@Module({\n imports: [\n BullModule.forRootAsync({\n imports: [ConfigModule],\n useFactory: (configService: ConfigService) => ({\n connection: {\n host: configService.get('REDIS_HOST', 'localhost'),\n port: configService.get('REDIS_PORT', 6379),\n password: configService.get('REDIS_PASSWORD') || undefined,\n },\n }),\n inject: [ConfigService],\n }),\n BullModule.registerQueue({ name: 'example' }),\n ],\n providers: [ExampleProcessor],\n exports: [BullModule],\n})\nexport class QueueModule {}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'queue', 'example.processor.ts'), `import { Processor, WorkerHost } from '@nestjs/bullmq';\nimport { Job } from 'bullmq';\n\n@Processor('example')\nexport class ExampleProcessor extends WorkerHost {\n async process(job: Job<{ message: string }>) {\n console.log(\\`Processando job \\${job.id}: \\${job.data.message}\\`);\n // TODO: Implemente a logica do job aqui\n return { success: true };\n }\n}\n`);\n\n dependencies['@nestjs/bullmq'] = deps['@nestjs/bullmq'];\n } else {\n await writeFile(path.join(apiDir, 'src', 'queue', 'queue.config.ts'), `import { Queue, Worker } from 'bullmq';\n\nconst connection = {\n host: process.env.REDIS_HOST || 'localhost',\n port: Number(process.env.REDIS_PORT) || 6379,\n password: process.env.REDIS_PASSWORD || undefined,\n};\n\nexport function createQueue(name: string) {\n return new Queue(name, { connection });\n}\n\nexport function createWorker(\n name: string,\n processor: (job: any) => Promise<any>\n) {\n const worker = new Worker(name, processor, { connection });\n\n worker.on('completed', (job) => {\n console.log(\\`Job \\${job.id} concluido\\`);\n });\n\n worker.on('failed', (job, err) => {\n console.error(\\`Job \\${job?.id} falhou:\\`, err);\n });\n\n return worker;\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'queue', 'example.worker.ts'), `import { createQueue, createWorker } from './queue.config.js';\n\n// Criar fila\nexport const exampleQueue = createQueue('example');\n\n// Criar worker\nexport const exampleWorker = createWorker('example', async (job) => {\n console.log(\\`Processando job \\${job.id}: \\${job.data.message}\\`);\n // TODO: Implemente a logica do job aqui\n return { success: true };\n});\n\n// Funcao helper para adicionar job na fila\nexport async function addExampleJob(data: { message: string }) {\n return exampleQueue.add('process', data);\n}\n`);\n }\n\n dependencies['bullmq'] = deps.bullmq;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const rabbitmqInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'queue'));\n\n envEntries.push(\n { key: 'RABBITMQ_URL', value: 'amqp://guest:guest@localhost:5672', category: 'RabbitMQ' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'queue', 'rabbitmq.config.ts'), `import { Module } from '@nestjs/common';\nimport { ClientsModule, Transport } from '@nestjs/microservices';\n\n@Module({\n imports: [\n ClientsModule.register([\n {\n name: 'RABBITMQ_SERVICE',\n transport: Transport.RMQ,\n options: {\n urls: [process.env.RABBITMQ_URL || 'amqp://guest:guest@localhost:5672'],\n queue: 'main_queue',\n queueOptions: { durable: true },\n },\n },\n ]),\n ],\n exports: [ClientsModule],\n})\nexport class RabbitMQModule {}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'queue', 'rabbitmq.consumer.ts'), `import { Controller } from '@nestjs/common';\nimport { MessagePattern, Payload } from '@nestjs/microservices';\n\n@Controller()\nexport class RabbitMQConsumer {\n @MessagePattern('example_pattern')\n async handleMessage(@Payload() data: any) {\n console.log('Mensagem recebida:', data);\n // TODO: Processar mensagem\n return { success: true };\n }\n}\n`);\n\n dependencies['@nestjs/microservices'] = deps['@nestjs/common'];\n } else {\n await writeFile(path.join(apiDir, 'src', 'queue', 'rabbitmq.ts'), `import amqplib, { type Channel, type Connection } from 'amqplib';\n\nlet connection: Connection | null = null;\nlet channel: Channel | null = null;\n\nexport async function connectRabbitMQ(): Promise<Channel> {\n const url = process.env.RABBITMQ_URL || 'amqp://guest:guest@localhost:5672';\n connection = await amqplib.connect(url);\n channel = await connection.createChannel();\n console.log('RabbitMQ conectado');\n return channel;\n}\n\nexport async function publishMessage(queue: string, message: unknown): Promise<void> {\n if (!channel) throw new Error('RabbitMQ nao conectado');\n await channel.assertQueue(queue, { durable: true });\n channel.sendToQueue(queue, Buffer.from(JSON.stringify(message)), { persistent: true });\n}\n\nexport async function consumeMessages(\n queue: string,\n handler: (msg: unknown) => Promise<void>\n): Promise<void> {\n if (!channel) throw new Error('RabbitMQ nao conectado');\n await channel.assertQueue(queue, { durable: true });\n channel.consume(queue, async (msg) => {\n if (!msg) return;\n try {\n const data = JSON.parse(msg.content.toString());\n await handler(data);\n channel!.ack(msg);\n } catch (err) {\n console.error('Erro ao processar mensagem:', err);\n channel!.nack(msg, false, true);\n }\n });\n}\n\nexport async function closeRabbitMQ(): Promise<void> {\n await channel?.close();\n await connection?.close();\n}\n`);\n }\n\n dependencies['amqplib'] = deps.amqplib;\n devDependencies['@types/amqplib'] = deps['@types/amqplib'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const redisInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'redis'));\n\n envEntries.push(\n { key: 'REDIS_HOST', value: 'localhost', category: 'Redis' },\n { key: 'REDIS_PORT', value: '6379', category: 'Redis' },\n { key: 'REDIS_PASSWORD', value: '', category: 'Redis' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'redis', 'redis.service.ts'), `import { Injectable, OnModuleDestroy } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Redis from 'ioredis';\n\n@Injectable()\nexport class RedisService implements OnModuleDestroy {\n public readonly client: Redis;\n\n constructor(private configService: ConfigService) {\n this.client = new Redis({\n host: this.configService.get('REDIS_HOST', 'localhost'),\n port: this.configService.get('REDIS_PORT', 6379),\n password: this.configService.get('REDIS_PASSWORD') || undefined,\n });\n }\n\n async get(key: string): Promise<string | null> {\n return this.client.get(key);\n }\n\n async set(key: string, value: string, ttlSeconds?: number): Promise<void> {\n if (ttlSeconds) {\n await this.client.set(key, value, 'EX', ttlSeconds);\n } else {\n await this.client.set(key, value);\n }\n }\n\n async del(key: string): Promise<void> {\n await this.client.del(key);\n }\n\n async onModuleDestroy() {\n await this.client.quit();\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'redis', 'redis.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { RedisService } from './redis.service';\n\n@Global()\n@Module({\n providers: [RedisService],\n exports: [RedisService],\n})\nexport class RedisModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'redis', 'redis.ts'), `import Redis from 'ioredis';\n\nconst redis = new Redis({\n host: process.env.REDIS_HOST || 'localhost',\n port: Number(process.env.REDIS_PORT) || 6379,\n password: process.env.REDIS_PASSWORD || undefined,\n});\n\nredis.on('connect', () => console.log('Redis conectado'));\nredis.on('error', (err) => console.error('Redis erro:', err));\n\nexport default redis;\n`);\n }\n\n dependencies['ioredis'] = deps.ioredis;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const smtpInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'email'));\n await ensureDir(path.join(apiDir, 'src', 'infra', 'email', 'templates'));\n\n envEntries.push(\n { key: 'SMTP_HOST', value: '', category: 'SMTP', comment: 'Ex: smtp.gmail.com' },\n { key: 'SMTP_PORT', value: '587', category: 'SMTP' },\n { key: 'SMTP_USER', value: '', category: 'SMTP' },\n { key: 'SMTP_PASS', value: '', category: 'SMTP' },\n { key: 'SMTP_FROM', value: `noreply@${config.projectName}.com`, category: 'SMTP' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'email.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport * as nodemailer from 'nodemailer';\n\n@Injectable()\nexport class EmailService {\n private transporter: nodemailer.Transporter;\n\n constructor(private configService: ConfigService) {\n this.transporter = nodemailer.createTransport({\n host: this.configService.get('SMTP_HOST'),\n port: this.configService.get('SMTP_PORT', 587),\n secure: false,\n auth: {\n user: this.configService.get('SMTP_USER'),\n pass: this.configService.get('SMTP_PASS'),\n },\n });\n }\n\n async sendEmail(to: string, subject: string, html: string): Promise<void> {\n await this.transporter.sendMail({\n from: this.configService.get('SMTP_FROM'),\n to,\n subject,\n html,\n });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'email.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { EmailService } from './email.service';\n\n@Global()\n@Module({\n providers: [EmailService],\n exports: [EmailService],\n})\nexport class EmailModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'email.service.ts'), `import nodemailer from 'nodemailer';\n\nconst transporter = nodemailer.createTransport({\n host: process.env.SMTP_HOST,\n port: Number(process.env.SMTP_PORT) || 587,\n secure: false,\n auth: {\n user: process.env.SMTP_USER,\n pass: process.env.SMTP_PASS,\n },\n});\n\nexport async function sendEmail(to: string, subject: string, html: string): Promise<void> {\n await transporter.sendMail({\n from: process.env.SMTP_FROM,\n to,\n subject,\n html,\n });\n}\n\nexport default { sendEmail };\n`);\n }\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'templates', 'welcome.html'), `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <style>\n body { font-family: system-ui, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }\n .container { max-width: 600px; margin: 0 auto; background: white; border-radius: 8px; padding: 40px; }\n h1 { color: #333; }\n .btn { display: inline-block; padding: 12px 24px; background: #0070f3; color: white; text-decoration: none; border-radius: 6px; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <h1>Bem-vindo ao ${config.projectName}!</h1>\n <p>Sua conta foi criada com sucesso.</p>\n <a href=\"{{APP_URL}}\" class=\"btn\">Acessar</a>\n </div>\n</body>\n</html>\n`);\n\n dependencies['nodemailer'] = deps.nodemailer;\n devDependencies['@types/nodemailer'] = deps['@types/nodemailer'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const minioInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'storage'));\n\n envEntries.push(\n { key: 'MINIO_ENDPOINT', value: 'localhost', category: 'MinIO Storage' },\n { key: 'MINIO_PORT', value: '9000', category: 'MinIO Storage' },\n { key: 'MINIO_ACCESS_KEY', value: 'minioadmin', category: 'MinIO Storage' },\n { key: 'MINIO_SECRET_KEY', value: 'minioadmin', category: 'MinIO Storage' },\n { key: 'MINIO_BUCKET', value: config.projectName.replace(/-/g, '-'), category: 'MinIO Storage' },\n { key: 'MINIO_USE_SSL', value: 'false', category: 'MinIO Storage' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'storage.service.ts'), `import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport * as Minio from 'minio';\n\n@Injectable()\nexport class StorageService implements OnModuleInit {\n private client: Minio.Client;\n private bucket: string;\n\n constructor(private configService: ConfigService) {\n this.bucket = this.configService.get('MINIO_BUCKET', '${config.projectName}');\n this.client = new Minio.Client({\n endPoint: this.configService.get('MINIO_ENDPOINT', 'localhost'),\n port: this.configService.get('MINIO_PORT', 9000),\n useSSL: this.configService.get('MINIO_USE_SSL') === 'true',\n accessKey: this.configService.get('MINIO_ACCESS_KEY', 'minioadmin'),\n secretKey: this.configService.get('MINIO_SECRET_KEY', 'minioadmin'),\n });\n }\n\n async onModuleInit() {\n const exists = await this.client.bucketExists(this.bucket);\n if (!exists) {\n await this.client.makeBucket(this.bucket);\n console.log(\\`Bucket \"\\${this.bucket}\" criado\\`);\n }\n }\n\n async upload(fileName: string, buffer: Buffer, contentType?: string): Promise<string> {\n await this.client.putObject(this.bucket, fileName, buffer, buffer.length, {\n 'Content-Type': contentType || 'application/octet-stream',\n });\n return fileName;\n }\n\n async getFileUrl(fileName: string, expirySeconds = 3600): Promise<string> {\n return this.client.presignedGetObject(this.bucket, fileName, expirySeconds);\n }\n\n async delete(fileName: string): Promise<void> {\n await this.client.removeObject(this.bucket, fileName);\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'storage.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { StorageService } from './storage.service';\n\n@Global()\n@Module({\n providers: [StorageService],\n exports: [StorageService],\n})\nexport class StorageModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'storage.ts'), `import * as Minio from 'minio';\n\nconst BUCKET = process.env.MINIO_BUCKET || '${config.projectName}';\n\nconst minioClient = new Minio.Client({\n endPoint: process.env.MINIO_ENDPOINT || 'localhost',\n port: Number(process.env.MINIO_PORT) || 9000,\n useSSL: process.env.MINIO_USE_SSL === 'true',\n accessKey: process.env.MINIO_ACCESS_KEY || 'minioadmin',\n secretKey: process.env.MINIO_SECRET_KEY || 'minioadmin',\n});\n\nexport async function initStorage(): Promise<void> {\n const exists = await minioClient.bucketExists(BUCKET);\n if (!exists) {\n await minioClient.makeBucket(BUCKET);\n console.log(\\`Bucket \"\\${BUCKET}\" criado\\`);\n }\n}\n\nexport async function upload(fileName: string, buffer: Buffer, contentType?: string): Promise<string> {\n await minioClient.putObject(BUCKET, fileName, buffer, buffer.length, {\n 'Content-Type': contentType || 'application/octet-stream',\n });\n return fileName;\n}\n\nexport async function getFileUrl(fileName: string, expirySeconds = 3600): Promise<string> {\n return minioClient.presignedGetObject(BUCKET, fileName, expirySeconds);\n}\n\nexport async function deleteFile(fileName: string): Promise<void> {\n await minioClient.removeObject(BUCKET, fileName);\n}\n\nexport default { initStorage, upload, getFileUrl, deleteFile };\n`);\n }\n\n dependencies['minio'] = deps.minio;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const pm2Installer: InstallerFn = async (opts) => {\n const { config, projectDir, devDependencies, scripts } = opts;\n\n const ecosystem = `module.exports = {\n apps: [\n {\n name: '${config.projectName}-api',\n script: '${config.backend === 'nestjs' ? 'dist/main.js' : 'dist/index.js'}',\n cwd: './apps/api',\n instances: 'max',\n exec_mode: 'cluster',\n env: {\n NODE_ENV: 'production',\n PORT: 3001,\n },\n watch: false,\n max_memory_restart: '1G',\n // Zero-downtime reload\n wait_ready: true,\n listen_timeout: 10000,\n kill_timeout: 5000,\n },\n ],\n};\n`;\n\n await writeFile(path.join(projectDir, 'ecosystem.config.cjs'), ecosystem);\n\n devDependencies['pm2'] = deps.pm2;\n scripts['pm2:start'] = 'pm2 start ecosystem.config.cjs';\n scripts['pm2:stop'] = 'pm2 stop ecosystem.config.cjs';\n scripts['pm2:restart'] = 'pm2 reload ecosystem.config.cjs';\n scripts['pm2:logs'] = 'pm2 logs';\n};\n","import path from 'path';\nimport type { InstallerFn } from '../types/installers.js';\nimport { ensureDir, writeFile } from '../helpers/filesystem.js';\n\nexport const multiTenantInstaller: InstallerFn = async (opts) => {\n const { config, apiDir } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'tenant'));\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'tenant', 'tenant.middleware.ts'), `import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\n\n@Injectable()\nexport class TenantMiddleware implements NestMiddleware {\n use(req: Request, _res: Response, next: NextFunction) {\n // Extrair tenant do header, subdomain ou path\n const tenantId = req.headers['x-tenant-id'] as string\n || this.extractFromSubdomain(req)\n || 'default';\n\n (req as any).tenantId = tenantId;\n next();\n }\n\n private extractFromSubdomain(req: Request): string | null {\n const host = req.hostname;\n const parts = host.split('.');\n if (parts.length >= 3) {\n return parts[0]; // subdomain como tenant\n }\n return null;\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'tenant', 'tenant.decorator.ts'), `import { createParamDecorator, ExecutionContext } from '@nestjs/common';\n\nexport const TenantId = createParamDecorator(\n (data: unknown, ctx: ExecutionContext): string => {\n const request = ctx.switchToHttp().getRequest();\n return request.tenantId || 'default';\n },\n);\n`);\n\n await writeFile(path.join(apiDir, 'src', 'tenant', 'tenant.module.ts'), `import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';\nimport { TenantMiddleware } from './tenant.middleware';\n\n@Module({})\nexport class TenantModule implements NestModule {\n configure(consumer: MiddlewareConsumer) {\n consumer.apply(TenantMiddleware).forRoutes('*');\n }\n}\n`);\n } else if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'tenant', 'tenant.middleware.ts'), `import type { Request, Response, NextFunction } from 'express';\n\nexport function tenantMiddleware(req: Request, _res: Response, next: NextFunction) {\n const tenantId = req.headers['x-tenant-id'] as string\n || extractFromSubdomain(req)\n || 'default';\n\n (req as any).tenantId = tenantId;\n next();\n}\n\nfunction extractFromSubdomain(req: Request): string | null {\n const host = req.hostname;\n const parts = host.split('.');\n if (parts.length >= 3) {\n return parts[0];\n }\n return null;\n}\n`);\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'tenant', 'tenant.plugin.ts'), `import type { FastifyInstance, FastifyRequest } from 'fastify';\nimport fp from 'fastify-plugin';\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n tenantId: string;\n }\n}\n\nasync function tenantPlugin(app: FastifyInstance) {\n app.decorateRequest('tenantId', 'default');\n\n app.addHook('onRequest', async (request: FastifyRequest) => {\n const tenantId = (request.headers['x-tenant-id'] as string)\n || extractFromSubdomain(request)\n || 'default';\n\n request.tenantId = tenantId;\n });\n}\n\nfunction extractFromSubdomain(request: FastifyRequest): string | null {\n const host = request.hostname;\n const parts = host.split('.');\n if (parts.length >= 3) {\n return parts[0];\n }\n return null;\n}\n\nexport default fp(tenantPlugin, { name: 'tenant' });\n`);\n }\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const viacepInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'viacep'));\n\n const serviceContent = `import axios from 'axios';\n\nexport interface ViaCepResponse {\n cep: string;\n logradouro: string;\n complemento: string;\n bairro: string;\n localidade: string;\n uf: string;\n ibge: string;\n erro?: boolean;\n}\n\nconst VIACEP_URL = 'https://viacep.com.br/ws';\n\nexport async function fetchAddress(cep: string): Promise<ViaCepResponse | null> {\n const cleanCep = cep.replace(/\\\\D/g, '');\n if (cleanCep.length !== 8) throw new Error('CEP deve ter 8 dígitos');\n\n const { data } = await axios.get<ViaCepResponse>(\\`\\${VIACEP_URL}/\\${cleanCep}/json\\`);\n if (data.erro) return null;\n return data;\n}\n`;\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'viacep', 'viacep.service.ts'), `import { Injectable } from '@nestjs/common';\nimport axios from 'axios';\n\nexport interface ViaCepResponse {\n cep: string;\n logradouro: string;\n complemento: string;\n bairro: string;\n localidade: string;\n uf: string;\n ibge: string;\n erro?: boolean;\n}\n\n@Injectable()\nexport class ViaCepService {\n private readonly baseUrl = 'https://viacep.com.br/ws';\n\n async fetchAddress(cep: string): Promise<ViaCepResponse | null> {\n const cleanCep = cep.replace(/\\\\D/g, '');\n if (cleanCep.length !== 8) throw new Error('CEP deve ter 8 dígitos');\n\n const { data } = await axios.get<ViaCepResponse>(\\`\\${this.baseUrl}/\\${cleanCep}/json\\`);\n if (data.erro) return null;\n return data;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'viacep', 'viacep.service.ts'), serviceContent);\n }\n\n dependencies['axios'] = deps.axios;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const whatsappInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'whatsapp'));\n\n envEntries.push(\n { key: 'WHATSAPP_API_TOKEN', value: '', category: 'WhatsApp', comment: 'Token da API Meta WhatsApp Business' },\n { key: 'WHATSAPP_PHONE_ID', value: '', category: 'WhatsApp' },\n { key: 'WHATSAPP_VERIFY_TOKEN', value: 'my-verify-token', category: 'WhatsApp', comment: 'Token de verificacao do webhook' },\n );\n\n const serviceContent = config.backend === 'nestjs'\n ? `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport axios from 'axios';\n\n@Injectable()\nexport class WhatsAppService {\n private readonly apiUrl: string;\n private readonly token: string;\n\n constructor(private configService: ConfigService) {\n const phoneId = this.configService.get('WHATSAPP_PHONE_ID');\n this.apiUrl = \\`https://graph.facebook.com/v18.0/\\${phoneId}/messages\\`;\n this.token = this.configService.get('WHATSAPP_API_TOKEN', '');\n }\n\n async sendMessage(to: string, message: string): Promise<void> {\n await axios.post(\n this.apiUrl,\n {\n messaging_product: 'whatsapp',\n to,\n type: 'text',\n text: { body: message },\n },\n {\n headers: {\n Authorization: \\`Bearer \\${this.token}\\`,\n 'Content-Type': 'application/json',\n },\n }\n );\n }\n\n async sendTemplate(to: string, templateName: string, language = 'pt_BR'): Promise<void> {\n await axios.post(\n this.apiUrl,\n {\n messaging_product: 'whatsapp',\n to,\n type: 'template',\n template: { name: templateName, language: { code: language } },\n },\n {\n headers: {\n Authorization: \\`Bearer \\${this.token}\\`,\n 'Content-Type': 'application/json',\n },\n }\n );\n }\n}\n`\n : `import axios from 'axios';\n\nconst PHONE_ID = process.env.WHATSAPP_PHONE_ID;\nconst API_URL = \\`https://graph.facebook.com/v18.0/\\${PHONE_ID}/messages\\`;\nconst TOKEN = process.env.WHATSAPP_API_TOKEN || '';\n\nconst headers = {\n Authorization: \\`Bearer \\${TOKEN}\\`,\n 'Content-Type': 'application/json',\n};\n\nexport async function sendMessage(to: string, message: string): Promise<void> {\n await axios.post(API_URL, {\n messaging_product: 'whatsapp',\n to,\n type: 'text',\n text: { body: message },\n }, { headers });\n}\n\nexport async function sendTemplate(to: string, templateName: string, language = 'pt_BR'): Promise<void> {\n await axios.post(API_URL, {\n messaging_product: 'whatsapp',\n to,\n type: 'template',\n template: { name: templateName, language: { code: language } },\n }, { headers });\n}\n`;\n\n await writeFile(path.join(apiDir, 'src', 'integrations', 'whatsapp', 'whatsapp.service.ts'), serviceContent);\n\n dependencies['axios'] = deps.axios;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const stripeInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'stripe'));\n\n envEntries.push(\n { key: 'STRIPE_SECRET_KEY', value: '', category: 'Stripe', comment: 'Obtenha em https://dashboard.stripe.com' },\n { key: 'STRIPE_WEBHOOK_SECRET', value: '', category: 'Stripe' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'stripe', 'stripe.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Stripe from 'stripe';\n\n@Injectable()\nexport class StripeService {\n private stripe: Stripe;\n\n constructor(private configService: ConfigService) {\n this.stripe = new Stripe(this.configService.get('STRIPE_SECRET_KEY', ''), {\n apiVersion: '2024-12-18.acacia',\n });\n }\n\n async createCheckoutSession(params: {\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n }) {\n return this.stripe.checkout.sessions.create({\n mode: 'subscription',\n payment_method_types: ['card'],\n line_items: [{ price: params.priceId, quantity: 1 }],\n success_url: params.successUrl,\n cancel_url: params.cancelUrl,\n customer_email: params.customerEmail,\n });\n }\n\n async createPaymentIntent(amount: number, currency = 'brl') {\n return this.stripe.paymentIntents.create({\n amount,\n currency,\n });\n }\n\n constructWebhookEvent(body: Buffer, signature: string) {\n const webhookSecret = this.configService.get('STRIPE_WEBHOOK_SECRET', '');\n return this.stripe.webhooks.constructEvent(body, signature, webhookSecret);\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'stripe', 'stripe.service.ts'), `import Stripe from 'stripe';\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY || '', {\n apiVersion: '2024-12-18.acacia',\n});\n\nexport async function createCheckoutSession(params: {\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n}) {\n return stripe.checkout.sessions.create({\n mode: 'subscription',\n payment_method_types: ['card'],\n line_items: [{ price: params.priceId, quantity: 1 }],\n success_url: params.successUrl,\n cancel_url: params.cancelUrl,\n customer_email: params.customerEmail,\n });\n}\n\nexport async function createPaymentIntent(amount: number, currency = 'brl') {\n return stripe.paymentIntents.create({ amount, currency });\n}\n\nexport function constructWebhookEvent(body: Buffer, signature: string) {\n return stripe.webhooks.constructEvent(\n body,\n signature,\n process.env.STRIPE_WEBHOOK_SECRET || ''\n );\n}\n`);\n }\n\n dependencies['stripe'] = deps.stripe;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const mercadoPagoInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'mercado-pago'));\n\n envEntries.push(\n { key: 'MERCADOPAGO_ACCESS_TOKEN', value: '', category: 'Mercado Pago', comment: 'Obtenha em https://www.mercadopago.com.br/developers' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'mercado-pago', 'mercado-pago.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { MercadoPagoConfig, Preference, Payment } from 'mercadopago';\n\n@Injectable()\nexport class MercadoPagoService {\n private client: MercadoPagoConfig;\n\n constructor(private configService: ConfigService) {\n this.client = new MercadoPagoConfig({\n accessToken: this.configService.get('MERCADOPAGO_ACCESS_TOKEN', ''),\n });\n }\n\n async createPreference(params: {\n title: string;\n quantity: number;\n unitPrice: number;\n successUrl?: string;\n failureUrl?: string;\n }) {\n const preference = new Preference(this.client);\n return preference.create({\n body: {\n items: [\n {\n id: 'item-1',\n title: params.title,\n quantity: params.quantity,\n unit_price: params.unitPrice,\n currency_id: 'BRL',\n },\n ],\n back_urls: {\n success: params.successUrl || 'http://localhost:3000/success',\n failure: params.failureUrl || 'http://localhost:3000/failure',\n },\n auto_return: 'approved',\n },\n });\n }\n\n async getPayment(paymentId: string) {\n const payment = new Payment(this.client);\n return payment.get({ id: paymentId });\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'mercado-pago', 'mercado-pago.service.ts'), `import { MercadoPagoConfig, Preference, Payment } from 'mercadopago';\n\nconst client = new MercadoPagoConfig({\n accessToken: process.env.MERCADOPAGO_ACCESS_TOKEN || '',\n});\n\nexport async function createPreference(params: {\n title: string;\n quantity: number;\n unitPrice: number;\n successUrl?: string;\n failureUrl?: string;\n}) {\n const preference = new Preference(client);\n return preference.create({\n body: {\n items: [\n {\n id: 'item-1',\n title: params.title,\n quantity: params.quantity,\n unit_price: params.unitPrice,\n currency_id: 'BRL',\n },\n ],\n back_urls: {\n success: params.successUrl || 'http://localhost:3000/success',\n failure: params.failureUrl || 'http://localhost:3000/failure',\n },\n auto_return: 'approved',\n },\n });\n}\n\nexport async function getPayment(paymentId: string) {\n const payment = new Payment(client);\n return payment.get({ id: paymentId });\n}\n`);\n }\n\n dependencies['mercadopago'] = deps.mercadopago;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const abacatePayInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'abacate-pay'));\n\n envEntries.push(\n { key: 'ABACATEPAY_API_KEY', value: '', category: 'AbacatePay', comment: 'Obtenha em https://abacatepay.com' },\n { key: 'ABACATEPAY_API_URL', value: 'https://api.abacatepay.com/v1', category: 'AbacatePay' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'abacate-pay', 'abacate-pay.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport axios, { type AxiosInstance } from 'axios';\n\n@Injectable()\nexport class AbacatePayService {\n private client: AxiosInstance;\n\n constructor(private configService: ConfigService) {\n this.client = axios.create({\n baseURL: this.configService.get('ABACATEPAY_API_URL', 'https://api.abacatepay.com/v1'),\n headers: {\n Authorization: \\`Bearer \\${this.configService.get('ABACATEPAY_API_KEY')}\\`,\n 'Content-Type': 'application/json',\n },\n });\n }\n\n async createPayment(params: {\n amount: number;\n description: string;\n customerEmail: string;\n }) {\n const { data } = await this.client.post('/payments', {\n amount: params.amount,\n description: params.description,\n customer: { email: params.customerEmail },\n });\n return data;\n }\n\n async getPayment(paymentId: string) {\n const { data } = await this.client.get(\\`/payments/\\${paymentId}\\`);\n return data;\n }\n\n async createPixPayment(params: {\n amount: number;\n description: string;\n customerEmail: string;\n }) {\n const { data } = await this.client.post('/payments/pix', {\n amount: params.amount,\n description: params.description,\n customer: { email: params.customerEmail },\n });\n return data;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'abacate-pay', 'abacate-pay.service.ts'), `import axios from 'axios';\n\nconst API_URL = process.env.ABACATEPAY_API_URL || 'https://api.abacatepay.com/v1';\nconst API_KEY = process.env.ABACATEPAY_API_KEY || '';\n\nconst client = axios.create({\n baseURL: API_URL,\n headers: {\n Authorization: \\`Bearer \\${API_KEY}\\`,\n 'Content-Type': 'application/json',\n },\n});\n\nexport async function createPayment(params: {\n amount: number;\n description: string;\n customerEmail: string;\n}) {\n const { data } = await client.post('/payments', {\n amount: params.amount,\n description: params.description,\n customer: { email: params.customerEmail },\n });\n return data;\n}\n\nexport async function getPayment(paymentId: string) {\n const { data } = await client.get(\\`/payments/\\${paymentId}\\`);\n return data;\n}\n\nexport async function createPixPayment(params: {\n amount: number;\n description: string;\n customerEmail: string;\n}) {\n const { data } = await client.post('/payments/pix', {\n amount: params.amount,\n description: params.description,\n customer: { email: params.customerEmail },\n });\n return data;\n}\n`);\n }\n\n dependencies['axios'] = deps.axios;\n};\n","import type { ProjectConfig } from '../types/config.js';\nimport type { InstallerMap } from '../types/installers.js';\n\nimport { prismaInstaller } from './database/prisma.js';\nimport { mongooseInstaller } from './database/mongoose.js';\nimport { jwtInstaller } from './auth/jwt.js';\nimport { magicLinkInstaller } from './auth/magicLink.js';\nimport { googleOauthInstaller } from './auth/googleOauth.js';\nimport { bullmqInstaller } from './queue/bullmq.js';\nimport { rabbitmqInstaller } from './queue/rabbitmq.js';\nimport { redisInstaller } from './infra/redis.js';\nimport { smtpInstaller } from './infra/smtp.js';\nimport { minioInstaller } from './infra/minio.js';\nimport { pm2Installer } from './infra/pm2.js';\nimport { multiTenantInstaller } from './multiTenant.js';\nimport { viacepInstaller } from './integrations/viacep.js';\nimport { whatsappInstaller } from './integrations/whatsapp.js';\nimport { stripeInstaller } from './integrations/stripe.js';\nimport { mercadoPagoInstaller } from './integrations/mercadoPago.js';\nimport { abacatePayInstaller } from './integrations/abacatePay.js';\n\nexport function buildInstallerMap(config: ProjectConfig): InstallerMap {\n return {\n // Database (must run before auth since auth may depend on user model)\n 'Prisma': {\n inUse: config.usePrisma,\n installer: prismaInstaller,\n },\n 'Mongoose': {\n inUse: config.useMongoose,\n installer: mongooseInstaller,\n },\n\n // Multi-tenant (after database)\n 'Multi-tenant': {\n inUse: config.multiTenant,\n installer: multiTenantInstaller,\n },\n\n // Infrastructure\n 'Redis': {\n inUse: config.redis,\n installer: redisInstaller,\n },\n 'SMTP': {\n inUse: config.smtp,\n installer: smtpInstaller,\n },\n 'MinIO': {\n inUse: config.minio,\n installer: minioInstaller,\n },\n 'PM2': {\n inUse: config.pm2,\n installer: pm2Installer,\n },\n\n // Auth\n 'JWT Auth': {\n inUse: config.auth.jwt,\n installer: jwtInstaller,\n },\n 'Magic Link': {\n inUse: config.auth.magicLink,\n installer: magicLinkInstaller,\n },\n 'Google OAuth': {\n inUse: config.auth.googleOAuth,\n installer: googleOauthInstaller,\n },\n\n // Queues\n 'BullMQ': {\n inUse: config.queue === 'bullmq',\n installer: bullmqInstaller,\n },\n 'RabbitMQ': {\n inUse: config.queue === 'rabbitmq',\n installer: rabbitmqInstaller,\n },\n\n // Integrations\n 'ViaCEP': {\n inUse: config.integrations.viacep,\n installer: viacepInstaller,\n },\n 'WhatsApp': {\n inUse: config.integrations.whatsapp,\n installer: whatsappInstaller,\n },\n 'Stripe': {\n inUse: config.integrations.stripe,\n installer: stripeInstaller,\n },\n 'Mercado Pago': {\n inUse: config.integrations.mercadoPago,\n installer: mercadoPagoInstaller,\n },\n 'AbacatePay': {\n inUse: config.integrations.abacatePay,\n installer: abacatePayInstaller,\n },\n };\n}\n","import ora, { type Ora } from 'ora';\n\nexport function createSpinner(text: string): Ora {\n return ora({ text, color: 'cyan' });\n}\n\nexport async function withSpinner<T>(text: string, fn: () => Promise<T>): Promise<T> {\n const spinner = createSpinner(text);\n spinner.start();\n try {\n const result = await fn();\n spinner.succeed();\n return result;\n } catch (error) {\n spinner.fail();\n throw error;\n }\n}\n","import { execa } from 'execa';\n\nexport async function initGit(projectDir: string): Promise<void> {\n await execa('git', ['init'], { cwd: projectDir });\n await execa('git', ['add', '-A'], { cwd: projectDir });\n await execa('git', ['commit', '-m', 'chore: initial commit from plazercli'], {\n cwd: projectDir,\n });\n}\n","import { readFile, writeFile } from './filesystem.js';\nimport path from 'path';\n\nexport interface PackageJson {\n name: string;\n version: string;\n private?: boolean;\n description?: string;\n type?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n workspaces?: string[];\n [key: string]: unknown;\n}\n\nexport async function readPackageJson(dir: string): Promise<PackageJson> {\n const content = await readFile(path.join(dir, 'package.json'));\n return JSON.parse(content);\n}\n\nexport async function writePackageJson(dir: string, pkg: PackageJson): Promise<void> {\n await writeFile(path.join(dir, 'package.json'), JSON.stringify(pkg, null, 2) + '\\n');\n}\n\nexport function addDependency(\n pkg: PackageJson,\n name: string,\n version: string\n): void {\n if (!pkg.dependencies) pkg.dependencies = {};\n pkg.dependencies[name] = version;\n}\n\nexport function addDevDependency(\n pkg: PackageJson,\n name: string,\n version: string\n): void {\n if (!pkg.devDependencies) pkg.devDependencies = {};\n pkg.devDependencies[name] = version;\n}\n\nexport function addScript(\n pkg: PackageJson,\n name: string,\n command: string\n): void {\n if (!pkg.scripts) pkg.scripts = {};\n pkg.scripts[name] = command;\n}\n\nexport function sortDeps(pkg: PackageJson): PackageJson {\n if (pkg.dependencies) {\n pkg.dependencies = Object.fromEntries(\n Object.entries(pkg.dependencies).sort(([a], [b]) => a.localeCompare(b))\n );\n }\n if (pkg.devDependencies) {\n pkg.devDependencies = Object.fromEntries(\n Object.entries(pkg.devDependencies).sort(([a], [b]) => a.localeCompare(b))\n );\n }\n return pkg;\n}\n","import { parseArgs } from './cli/args.js';\nimport { runPrompts } from './cli/prompts.js';\nimport { printBanner, printSummary, logger } from './helpers/logger.js';\nimport { generateProject } from './generators/project.js';\nimport { confirm } from '@inquirer/prompts';\n\nasync function main() {\n const flags = parseArgs();\n\n printBanner();\n const config = await runPrompts(flags);\n\n printSummary(config);\n\n const confirmed = await confirm({\n message: '✅ Confirma a criação do projeto com essas configurações?',\n default: true,\n });\n\n if (!confirmed) {\n logger.warn('Criação cancelada.');\n process.exit(0);\n }\n\n await generateProject(config);\n}\n\nmain().catch((error) => {\n logger.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n});\n"],"mappings":"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","names":["path","path","chalk","path","path","fileURLToPath","__dirname","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","execa","path","pkg","pkg","path","chalk","confirm"]}
1
+ {"version":3,"sources":["../src/cli/args.ts","../src/cli/prompts.ts","../src/cli/presets.ts","../src/helpers/filesystem.ts","../src/helpers/logger.ts","../src/generators/project.ts","../src/generators/base.ts","../src/helpers/template.ts","../src/helpers/runtime.ts","../src/generators/frontend.ts","../src/installers/dependencyVersionMap.ts","../src/generators/backend.ts","../src/generators/docker.ts","../src/generators/env.ts","../src/generators/readme.ts","../src/generators/wiring.ts","../src/generators/liz.ts","../src/generators/cicd.ts","../src/generators/tailwind.ts","../src/helpers/packages.ts","../src/installers/database/prisma.ts","../src/installers/database/mongoose.ts","../src/installers/auth/jwt.ts","../src/installers/auth/magicLink.ts","../src/installers/auth/googleOauth.ts","../src/installers/queue/bullmq.ts","../src/installers/queue/rabbitmq.ts","../src/installers/infra/redis.ts","../src/installers/infra/smtp.ts","../src/installers/infra/minio.ts","../src/installers/infra/pm2.ts","../src/installers/multiTenant.ts","../src/installers/integrations/viacep.ts","../src/installers/integrations/whatsapp.ts","../src/installers/integrations/stripe.ts","../src/installers/integrations/mercadoPago.ts","../src/installers/integrations/abacatePay.ts","../src/installers/api/zod.ts","../src/installers/api/rateLimiting.ts","../src/installers/api/logging.ts","../src/installers/api/swagger.ts","../src/installers/saas/rbac.ts","../src/installers/saas/organizations.ts","../src/installers/saas/stripeBilling.ts","../src/installers/infra/websockets.ts","../src/installers/infra/i18n.ts","../src/installers/index.ts","../src/helpers/spinner.ts","../src/helpers/git.ts","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport path from 'path';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n// Works from both src/cli/ (dev) and dist/ (built)\nconst pkgPath = path.resolve(__dirname, '../package.json');\nconst pkgPathAlt = path.resolve(__dirname, '../../package.json');\nconst pkg = JSON.parse(\n (() => {\n try { return readFileSync(pkgPath, 'utf-8'); }\n catch { return readFileSync(pkgPathAlt, 'utf-8'); }\n })()\n);\n\nexport interface CliFlags {\n name?: string;\n yes?: boolean;\n preset?: string;\n dryRun?: boolean;\n saveConfig?: string;\n config?: string;\n}\n\nexport function parseArgs(): CliFlags {\n const program = new Command();\n\n program\n .name('plazercli')\n .description('CLI para gerar projetos fullstack SaaS boilerplate')\n .version(pkg.version, '-v, --version')\n .option('-n, --name <name>', 'Nome do projeto')\n .option('-y, --yes', 'Usar valores padrao (skip prompts)')\n .option('-p, --preset <preset>', 'Usar preset (saas-starter, ecommerce, api-platform, realtime-app, minimal)')\n .option('--dry-run', 'Mostrar o que seria gerado sem criar arquivos')\n .option('--save-config <path>', 'Salvar configuracao em arquivo JSON')\n .option('--config <path>', 'Carregar configuracao de arquivo JSON')\n .parse();\n\n const opts = program.opts();\n return {\n name: opts.name,\n yes: opts.yes,\n preset: opts.preset,\n dryRun: opts.dryRun,\n saveConfig: opts.saveConfig,\n config: opts.config,\n };\n}\n","import { input, select, confirm, checkbox } from '@inquirer/prompts';\nimport validateNpmPackageName from 'validate-npm-package-name';\nimport type { ProjectConfig } from '../types/config.js';\nimport type { CliFlags } from './args.js';\nimport { presets, getPreset } from './presets.js';\nimport { pathExists } from '../helpers/filesystem.js';\nimport { logger } from '../helpers/logger.js';\nimport path from 'path';\nimport fs from 'fs-extra';\n\nfunction getDefaults(): Omit<ProjectConfig, 'projectDir' | 'usePrisma' | 'useMongoose' | 'hasAnyAuth' | 'hasAnyIntegration' | 'hasAnyQueue'> {\n return {\n projectName: 'my-saas',\n projectDescription: 'Meu projeto SaaS',\n runtime: 'pnpm',\n database: 'postgresql',\n multiTenant: false,\n smtp: true,\n redis: true,\n minio: false,\n pm2: true,\n auth: { jwt: true, magicLink: false, googleOAuth: false },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: { viacep: false, whatsapp: false, stripe: false, mercadoPago: false, abacatePay: false },\n rbac: true,\n organizations: false,\n stripeBilling: false,\n zod: true,\n rateLimiting: true,\n logging: true,\n swagger: true,\n tailwind: true,\n cicd: true,\n websockets: false,\n i18n: false,\n };\n}\n\nexport async function runPrompts(flags: CliFlags): Promise<ProjectConfig> {\n // Load config from file if --config flag\n if (flags.config) {\n try {\n const configFile = await fs.readFile(flags.config, 'utf-8');\n const savedConfig = JSON.parse(configFile) as ProjectConfig;\n savedConfig.projectDir = path.resolve(process.cwd(), savedConfig.projectName);\n logger.success(`Configuracao carregada de ${flags.config}`);\n return savedConfig;\n } catch {\n logger.error(`Erro ao ler arquivo de configuracao: ${flags.config}`);\n process.exit(1);\n }\n }\n\n // 1. Preset ou modo custom\n let presetConfig: ReturnType<typeof getPreset> | undefined;\n\n if (flags.preset) {\n presetConfig = getPreset(flags.preset);\n if (!presetConfig) {\n logger.error(`Preset \"${flags.preset}\" nao encontrado. Disponiveis: ${Object.keys(presets).join(', ')}`);\n process.exit(1);\n }\n logger.success(`Usando preset: ${presetConfig.name}`);\n } else if (!flags.yes) {\n const mode = await select({\n message: '🚀 Como voce quer criar o projeto?',\n choices: [\n { name: 'Custom (escolher tudo)', value: 'custom' },\n ...Object.entries(presets).map(([key, p]) => ({\n name: `${p.name} — ${p.description}`,\n value: key,\n })),\n ],\n });\n\n if (mode !== 'custom') {\n presetConfig = getPreset(mode);\n }\n }\n\n const useYes = flags.yes === true;\n const defaults = getDefaults();\n\n // 2. Nome do projeto\n let projectName: string;\n if (flags.name) {\n projectName = flags.name;\n } else if (useYes) {\n projectName = defaults.projectName;\n } else {\n projectName = await input({\n message: '📦 Qual o nome do projeto?',\n validate: (value) => {\n if (!value.trim()) return 'O nome do projeto e obrigatorio';\n const validation = validateNpmPackageName(value);\n if (!validation.validForNewPackages) {\n return validation.errors?.[0] || validation.warnings?.[0] || 'Nome invalido para pacote npm';\n }\n return true;\n },\n });\n }\n\n // Check if directory already exists\n const projectDir = path.resolve(process.cwd(), projectName);\n if (await pathExists(projectDir)) {\n if (useYes) {\n logger.error(`Diretorio \"${projectName}\" ja existe. Escolha outro nome.`);\n process.exit(1);\n }\n const overwrite = await confirm({\n message: `⚠️ Diretorio \"${projectName}\" ja existe. Deseja sobrescrever?`,\n default: false,\n });\n if (!overwrite) {\n logger.warn('Criacao cancelada.');\n process.exit(0);\n }\n await fs.remove(projectDir);\n }\n\n // If using preset, use preset values\n if (presetConfig) {\n const pc = presetConfig.config;\n\n const projectDescription = useYes\n ? defaults.projectDescription\n : await input({\n message: '📝 Descreva brevemente o projeto:',\n default: `Projeto ${projectName}`,\n });\n\n return computeConfig({\n ...pc,\n projectName,\n projectDescription,\n projectDir,\n });\n }\n\n // 3. Descricao\n const projectDescription = useYes\n ? defaults.projectDescription\n : await input({\n message: '📝 Descreva brevemente o projeto:',\n default: `Projeto ${projectName}`,\n });\n\n // 4. Runtime / Package Manager\n const runtime = useYes\n ? defaults.runtime\n : await select({\n message: '⚡ Qual runtime/gerenciador de pacotes usar?',\n choices: [\n { name: 'pnpm (Recomendado)', value: 'pnpm' as const },\n { name: 'bun', value: 'bun' as const },\n { name: 'npm', value: 'npm' as const },\n ],\n });\n\n // 5. Banco de dados\n const database = useYes\n ? defaults.database\n : await select({\n message: '🗄️ Qual banco de dados usar?',\n choices: [\n { name: 'PostgreSQL (Recomendado para SaaS)', value: 'postgresql' as const },\n { name: 'MySQL', value: 'mysql' as const },\n { name: 'MongoDB', value: 'mongodb' as const },\n { name: 'Nenhum', value: 'none' as const },\n ],\n });\n\n // 6. Frontend\n const frontend = useYes\n ? defaults.frontend\n : await select({\n message: '🎨 Qual framework de frontend?',\n choices: [\n { name: 'Next.js (Recomendado)', value: 'nextjs' as const },\n { name: 'React (Vite)', value: 'react-vite' as const },\n { name: 'Vue', value: 'vue' as const },\n { name: 'Angular', value: 'angular' as const },\n ],\n });\n\n // 7. Backend\n const backend = useYes\n ? defaults.backend\n : await select({\n message: '🔧 Qual framework de backend?',\n choices: [\n { name: 'NestJS (Recomendado para SaaS)', value: 'nestjs' as const },\n { name: 'Express', value: 'express' as const },\n { name: 'Fastify', value: 'fastify' as const },\n ],\n });\n\n // 8. Autenticacao\n const authChoices = useYes\n ? ['jwt']\n : await checkbox({\n message: '🔐 Quais metodos de autenticacao usar?',\n choices: [\n { name: 'JWT (JSON Web Token)', value: 'jwt', checked: true },\n { name: 'Magic Link (login por email)', value: 'magicLink' },\n { name: 'Google OAuth', value: 'googleOAuth' },\n ],\n });\n\n const auth = {\n jwt: authChoices.includes('jwt'),\n magicLink: authChoices.includes('magicLink'),\n googleOAuth: authChoices.includes('googleOAuth'),\n };\n\n // 9. SaaS Features\n let rbac = false;\n let organizations = false;\n let stripeBilling = false;\n\n if (!useYes) {\n const saasFeatures = await checkbox({\n message: '💼 Quais features SaaS incluir?',\n choices: [\n { name: 'RBAC (Roles e Permissoes)', value: 'rbac', checked: true },\n { name: 'Organizations/Workspaces (times e convites)', value: 'organizations' },\n { name: 'Stripe Billing (planos, assinaturas, trials)', value: 'stripeBilling' },\n ],\n });\n rbac = saasFeatures.includes('rbac');\n organizations = saasFeatures.includes('organizations');\n stripeBilling = saasFeatures.includes('stripeBilling');\n } else {\n rbac = defaults.rbac;\n organizations = defaults.organizations;\n stripeBilling = defaults.stripeBilling;\n }\n\n // 10. API Quality\n let zod = false;\n let rateLimiting = false;\n let logging = false;\n let swagger = false;\n\n if (!useYes) {\n const apiFeatures = await checkbox({\n message: '🛡️ Quais features de API incluir?',\n choices: [\n { name: 'Zod (validacao de input)', value: 'zod', checked: true },\n { name: 'Rate Limiting (protecao contra abuso)', value: 'rateLimiting', checked: true },\n { name: 'Pino (logging estruturado)', value: 'logging', checked: true },\n { name: 'Swagger/OpenAPI (documentacao automatica)', value: 'swagger', checked: true },\n ],\n });\n zod = apiFeatures.includes('zod');\n rateLimiting = apiFeatures.includes('rateLimiting');\n logging = apiFeatures.includes('logging');\n swagger = apiFeatures.includes('swagger');\n } else {\n zod = defaults.zod;\n rateLimiting = defaults.rateLimiting;\n logging = defaults.logging;\n swagger = defaults.swagger;\n }\n\n // 11. Multi-tenant\n const multiTenant = useYes\n ? defaults.multiTenant\n : await confirm({\n message: '🏢 Usar multi-tenant?',\n default: false,\n });\n\n // 12. SMTP\n let smtp = useYes\n ? defaults.smtp\n : await confirm({\n message: '📧 Configurar servidor SMTP (envio de emails)?',\n default: true,\n });\n\n // Auto-habilitar SMTP se Magic Link selecionado\n if (auth.magicLink && !smtp) {\n smtp = true;\n console.log(' ℹ SMTP habilitado automaticamente (necessario para Magic Link)');\n }\n\n // 13. Redis\n let redis = useYes\n ? defaults.redis\n : await confirm({\n message: '🔴 Usar Redis (cache/sessoes)?',\n default: true,\n });\n\n // 14. Filas e Jobs\n const queue = useYes\n ? defaults.queue\n : await select({\n message: '📬 Usar filas e jobs?',\n choices: [\n { name: 'BullMQ (requer Redis)', value: 'bullmq' as const },\n { name: 'RabbitMQ', value: 'rabbitmq' as const },\n { name: 'Nenhum', value: 'none' as const },\n ],\n });\n\n // Auto-habilitar Redis se BullMQ\n if (queue === 'bullmq' && !redis) {\n redis = true;\n console.log(' ℹ Redis habilitado automaticamente (necessario para BullMQ)');\n }\n\n // 15. Integracoes\n const integrationChoices = useYes\n ? []\n : await checkbox({\n message: '🔌 Quais integracoes usar?',\n choices: [\n { name: 'ViaCEP (consulta CEP)', value: 'viacep' },\n { name: 'WhatsApp', value: 'whatsapp' },\n { name: 'Stripe (pagamentos)', value: 'stripe' },\n { name: 'Mercado Pago (pagamentos)', value: 'mercadoPago' },\n { name: 'AbacatePay (pagamentos)', value: 'abacatePay' },\n ],\n });\n\n const integrations = {\n viacep: integrationChoices.includes('viacep'),\n whatsapp: integrationChoices.includes('whatsapp'),\n stripe: integrationChoices.includes('stripe') || stripeBilling,\n mercadoPago: integrationChoices.includes('mercadoPago'),\n abacatePay: integrationChoices.includes('abacatePay'),\n };\n\n // 16. MinIO\n const minio = useYes\n ? defaults.minio\n : await confirm({\n message: '📦 Usar MinIO para storage (S3-compatible)?',\n default: false,\n });\n\n // 17. Extras\n let tailwind = true;\n let cicd = false;\n let websockets = false;\n let i18n = false;\n\n if (!useYes) {\n const extras = await checkbox({\n message: '✨ Extras?',\n choices: [\n { name: 'Tailwind CSS', value: 'tailwind', checked: true },\n { name: 'CI/CD (GitHub Actions + Dockerfile)', value: 'cicd' },\n { name: 'WebSockets (tempo real)', value: 'websockets' },\n { name: 'i18n (internacionalizacao)', value: 'i18n' },\n ],\n });\n tailwind = extras.includes('tailwind');\n cicd = extras.includes('cicd');\n websockets = extras.includes('websockets');\n i18n = extras.includes('i18n');\n } else {\n tailwind = defaults.tailwind;\n cicd = defaults.cicd;\n websockets = defaults.websockets;\n i18n = defaults.i18n;\n }\n\n // 18. PM2\n const pm2 = useYes\n ? defaults.pm2\n : await confirm({\n message: '🔄 Usar PM2 para atualizacoes sem downtime?',\n default: true,\n });\n\n return computeConfig({\n projectName,\n projectDescription,\n runtime,\n database,\n multiTenant,\n smtp,\n redis,\n minio,\n pm2,\n auth,\n queue,\n frontend,\n backend,\n integrations,\n rbac,\n organizations,\n stripeBilling,\n zod,\n rateLimiting,\n logging,\n swagger,\n tailwind,\n cicd,\n websockets,\n i18n,\n projectDir,\n });\n}\n\nfunction computeConfig(partial: Omit<ProjectConfig, 'usePrisma' | 'useMongoose' | 'hasAnyAuth' | 'hasAnyIntegration' | 'hasAnyQueue'> & { projectDir: string }): ProjectConfig {\n return {\n ...partial,\n usePrisma: partial.database === 'postgresql' || partial.database === 'mysql',\n useMongoose: partial.database === 'mongodb',\n hasAnyAuth: partial.auth.jwt || partial.auth.magicLink || partial.auth.googleOAuth,\n hasAnyIntegration: Object.values(partial.integrations).some(Boolean),\n hasAnyQueue: partial.queue !== 'none',\n };\n}\n","import type { ProjectConfig } from '../types/config.js';\n\ntype PresetConfig = Omit<ProjectConfig, 'projectName' | 'projectDescription' | 'projectDir' | 'usePrisma' | 'useMongoose' | 'hasAnyAuth' | 'hasAnyIntegration' | 'hasAnyQueue'>;\n\nexport interface Preset {\n name: string;\n description: string;\n config: PresetConfig;\n}\n\nexport const presets: Record<string, Preset> = {\n 'saas-starter': {\n name: 'SaaS Starter',\n description: 'Stack completa para SaaS: auth, billing, RBAC, dashboard',\n config: {\n runtime: 'pnpm',\n database: 'postgresql',\n multiTenant: false,\n smtp: true,\n redis: true,\n minio: false,\n pm2: true,\n auth: { jwt: true, magicLink: true, googleOAuth: true },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: { viacep: false, whatsapp: false, stripe: true, mercadoPago: false, abacatePay: false },\n rbac: true,\n organizations: true,\n stripeBilling: true,\n zod: true,\n rateLimiting: true,\n logging: true,\n swagger: true,\n tailwind: true,\n cicd: true,\n websockets: false,\n i18n: false,\n },\n },\n 'saas-multi-tenant': {\n name: 'SaaS Multi-Tenant',\n description: 'SaaS com isolamento por tenant, ideal para B2B',\n config: {\n runtime: 'pnpm',\n database: 'postgresql',\n multiTenant: true,\n smtp: true,\n redis: true,\n minio: true,\n pm2: true,\n auth: { jwt: true, magicLink: false, googleOAuth: true },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: { viacep: false, whatsapp: false, stripe: true, mercadoPago: false, abacatePay: false },\n rbac: true,\n organizations: true,\n stripeBilling: true,\n zod: true,\n rateLimiting: true,\n logging: true,\n swagger: true,\n tailwind: true,\n cicd: true,\n websockets: false,\n i18n: false,\n },\n },\n 'ecommerce': {\n name: 'E-commerce',\n description: 'Loja online com pagamentos, storage e email',\n config: {\n runtime: 'pnpm',\n database: 'postgresql',\n multiTenant: false,\n smtp: true,\n redis: true,\n minio: true,\n pm2: true,\n auth: { jwt: true, magicLink: false, googleOAuth: true },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: { viacep: true, whatsapp: true, stripe: true, mercadoPago: true, abacatePay: false },\n rbac: true,\n organizations: false,\n stripeBilling: false,\n zod: true,\n rateLimiting: true,\n logging: true,\n swagger: true,\n tailwind: true,\n cicd: true,\n websockets: false,\n i18n: false,\n },\n },\n 'api-platform': {\n name: 'API Platform',\n description: 'API robusta com docs, rate limiting, logging e monitoramento',\n config: {\n runtime: 'pnpm',\n database: 'postgresql',\n multiTenant: false,\n smtp: false,\n redis: true,\n minio: false,\n pm2: true,\n auth: { jwt: true, magicLink: false, googleOAuth: false },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'fastify',\n integrations: { viacep: false, whatsapp: false, stripe: false, mercadoPago: false, abacatePay: false },\n rbac: true,\n organizations: false,\n stripeBilling: false,\n zod: true,\n rateLimiting: true,\n logging: true,\n swagger: true,\n tailwind: true,\n cicd: true,\n websockets: false,\n i18n: false,\n },\n },\n 'realtime-app': {\n name: 'Realtime App',\n description: 'App com WebSockets, filas e Redis para comunicacao em tempo real',\n config: {\n runtime: 'pnpm',\n database: 'postgresql',\n multiTenant: false,\n smtp: false,\n redis: true,\n minio: false,\n pm2: true,\n auth: { jwt: true, magicLink: false, googleOAuth: false },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: { viacep: false, whatsapp: false, stripe: false, mercadoPago: false, abacatePay: false },\n rbac: false,\n organizations: false,\n stripeBilling: false,\n zod: true,\n rateLimiting: true,\n logging: true,\n swagger: true,\n tailwind: true,\n cicd: true,\n websockets: true,\n i18n: false,\n },\n },\n 'minimal': {\n name: 'Minimal',\n description: 'Minimo necessario: frontend + backend + banco',\n config: {\n runtime: 'pnpm',\n database: 'postgresql',\n multiTenant: false,\n smtp: false,\n redis: false,\n minio: false,\n pm2: false,\n auth: { jwt: false, magicLink: false, googleOAuth: false },\n queue: 'none',\n frontend: 'nextjs',\n backend: 'express',\n integrations: { viacep: false, whatsapp: false, stripe: false, mercadoPago: false, abacatePay: false },\n rbac: false,\n organizations: false,\n stripeBilling: false,\n zod: false,\n rateLimiting: false,\n logging: false,\n swagger: false,\n tailwind: true,\n cicd: false,\n websockets: false,\n i18n: false,\n },\n },\n};\n\nexport function getPresetNames(): string[] {\n return Object.keys(presets);\n}\n\nexport function getPreset(name: string): Preset | undefined {\n return presets[name];\n}\n","import fs from 'fs-extra';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n// Resolve templates dir from both src/helpers/ (dev) and dist/ (built)\nconst TEMPLATE_DIR = fs.existsSync(path.resolve(__dirname, '../../templates'))\n ? path.resolve(__dirname, '../../templates')\n : path.resolve(__dirname, '../templates');\n\nexport function getTemplatePath(...segments: string[]): string {\n return path.join(TEMPLATE_DIR, ...segments);\n}\n\nexport async function ensureDir(dir: string): Promise<void> {\n await fs.ensureDir(dir);\n}\n\nexport async function copyDir(src: string, dest: string): Promise<void> {\n await fs.copy(src, dest, { overwrite: true });\n}\n\nexport async function copyFile(src: string, dest: string): Promise<void> {\n await fs.ensureDir(path.dirname(dest));\n await fs.copyFile(src, dest);\n}\n\nexport async function writeFile(filePath: string, content: string): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\nexport async function readFile(filePath: string): Promise<string> {\n return fs.readFile(filePath, 'utf-8');\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n return fs.pathExists(filePath);\n}\n","import chalk from 'chalk';\n\nexport const logger = {\n info: (msg: string) => console.log(chalk.cyan(' i'), msg),\n success: (msg: string) => console.log(chalk.green(' +'), msg),\n warn: (msg: string) => console.log(chalk.yellow(' !'), msg),\n error: (msg: string) => console.log(chalk.red(' x'), msg),\n step: (msg: string) => console.log(chalk.blue(' >'), msg),\n title: (msg: string) => console.log(chalk.bold.white(`\\n ${msg}\\n`)),\n blank: () => console.log(),\n};\n\nexport function printBanner() {\n console.log(\n chalk.bold.cyan(`\n ╔═══════════════════════════════════════════════╗\n ║ ║\n ║ PlazerCLI v2.0 ║\n ║ Fullstack SaaS Boilerplate Generator ║\n ║ ║\n ║ Oi! Eu sou a Liz, sua assistente. ║\n ║ Vou configurar seu projeto inteiro. ║\n ║ ║\n ╚═══════════════════════════════════════════════╝\n`)\n );\n}\n\nexport function printSummary(config: {\n projectName: string;\n frontend: string;\n backend: string;\n database: string;\n auth: { jwt: boolean; magicLink: boolean; googleOAuth: boolean };\n queue: string;\n redis: boolean;\n smtp: boolean;\n minio: boolean;\n pm2: boolean;\n multiTenant: boolean;\n integrations: Record<string, boolean>;\n rbac: boolean;\n organizations: boolean;\n stripeBilling: boolean;\n zod: boolean;\n rateLimiting: boolean;\n logging: boolean;\n swagger: boolean;\n tailwind: boolean;\n cicd: boolean;\n websockets: boolean;\n i18n: boolean;\n}) {\n const authMethods = [\n config.auth.jwt && 'JWT',\n config.auth.magicLink && 'Magic Link',\n config.auth.googleOAuth && 'Google OAuth',\n ].filter(Boolean);\n\n const integrations = Object.entries(config.integrations)\n .filter(([, v]) => v)\n .map(([k]) => k);\n\n const saasFeatures = [\n config.rbac && 'RBAC',\n config.organizations && 'Organizations',\n config.stripeBilling && 'Stripe Billing',\n ].filter(Boolean);\n\n const apiFeatures = [\n config.zod && 'Zod',\n config.rateLimiting && 'Rate Limiting',\n config.logging && 'Pino',\n config.swagger && 'Swagger',\n ].filter(Boolean);\n\n const infra = [\n config.redis && 'Redis',\n config.smtp && 'SMTP',\n config.minio && 'MinIO',\n config.pm2 && 'PM2',\n config.multiTenant && 'Multi-tenant',\n config.websockets && 'WebSockets',\n ].filter(Boolean);\n\n const extras = [\n config.tailwind && 'Tailwind CSS',\n config.cicd && 'CI/CD',\n config.i18n && 'i18n',\n ].filter(Boolean);\n\n console.log(chalk.bold.white('\\n Liz preparou o resumo do projeto:\\n'));\n console.log(chalk.white(` Projeto: ${chalk.cyan(config.projectName)}`));\n console.log(chalk.white(` Frontend: ${chalk.cyan(config.frontend)}`));\n console.log(chalk.white(` Backend: ${chalk.cyan(config.backend)}`));\n console.log(chalk.white(` Banco de dados: ${chalk.cyan(config.database)}`));\n if (authMethods.length > 0) {\n console.log(chalk.white(` Autenticacao: ${chalk.cyan(authMethods.join(', '))}`));\n }\n if (saasFeatures.length > 0) {\n console.log(chalk.white(` SaaS: ${chalk.cyan(saasFeatures.join(', '))}`));\n }\n if (apiFeatures.length > 0) {\n console.log(chalk.white(` API: ${chalk.cyan(apiFeatures.join(', '))}`));\n }\n if (config.queue !== 'none') {\n console.log(chalk.white(` Filas: ${chalk.cyan(config.queue)}`));\n }\n if (infra.length > 0) {\n console.log(chalk.white(` Infra: ${chalk.cyan(infra.join(', '))}`));\n }\n if (integrations.length > 0) {\n console.log(chalk.white(` Integracoes: ${chalk.cyan(integrations.join(', '))}`));\n }\n if (extras.length > 0) {\n console.log(chalk.white(` Extras: ${chalk.cyan(extras.join(', '))}`));\n }\n console.log();\n}\n","import path from 'path';\nimport chalk from 'chalk';\nimport type { ProjectConfig, EnvEntry } from '../types/config.js';\nimport type { InstallerOptions } from '../types/installers.js';\nimport { generateBase } from './base.js';\nimport { generateFrontend } from './frontend.js';\nimport { generateBackend } from './backend.js';\nimport { generateDocker } from './docker.js';\nimport { generateEnv } from './env.js';\nimport { generateReadme } from './readme.js';\nimport { generateWiring } from './wiring.js';\nimport { generateLiz } from './liz.js';\nimport { generateCICD } from './cicd.js';\nimport { setupTailwind } from './tailwind.js';\nimport { buildInstallerMap } from '../installers/index.js';\nimport { withSpinner } from '../helpers/spinner.js';\nimport { installDependencies } from '../helpers/runtime.js';\nimport { initGit } from '../helpers/git.js';\nimport { logger } from '../helpers/logger.js';\nimport { readPackageJson, writePackageJson, sortDeps } from '../helpers/packages.js';\nimport { getRunCommand } from '../helpers/runtime.js';\n\nexport async function generateProject(config: ProjectConfig): Promise<void> {\n const projectDir = config.projectDir;\n const apiDir = path.join(projectDir, 'apps', 'api');\n const webDir = path.join(projectDir, 'apps', 'web');\n\n const envEntries: EnvEntry[] = [];\n const dependencies: Record<string, string> = {};\n const devDependencies: Record<string, string> = {};\n const scripts: Record<string, string> = {};\n const dockerServices: string[] = [];\n\n const opts: InstallerOptions = {\n config,\n projectDir,\n apiDir,\n webDir,\n envEntries,\n dependencies,\n devDependencies,\n scripts,\n dockerServices,\n };\n\n console.log(chalk.cyan('\\n Liz esta preparando seu projeto...\\n'));\n\n // 1. Base monorepo structure\n await withSpinner('Criando estrutura do monorepo...', async () => {\n await generateBase(config);\n });\n\n // 2. Frontend\n await withSpinner(`Configurando frontend (${config.frontend})...`, async () => {\n await generateFrontend(config, webDir);\n });\n\n // 3. Backend\n await withSpinner(`Configurando backend (${config.backend})...`, async () => {\n await generateBackend(config, apiDir);\n });\n\n // 4. Run installers\n const installerMap = buildInstallerMap(config);\n for (const [name, entry] of Object.entries(installerMap)) {\n if (entry.inUse) {\n await withSpinner(`Configurando ${name}...`, async () => {\n await entry.installer(opts);\n });\n }\n }\n\n // 5. Merge accumulated dependencies into API package.json\n if (Object.keys(dependencies).length > 0 || Object.keys(devDependencies).length > 0 || Object.keys(scripts).length > 0) {\n const apiPkg = await readPackageJson(apiDir);\n if (!apiPkg.dependencies) apiPkg.dependencies = {};\n if (!apiPkg.devDependencies) apiPkg.devDependencies = {};\n if (!apiPkg.scripts) apiPkg.scripts = {};\n Object.assign(apiPkg.dependencies, dependencies);\n Object.assign(apiPkg.devDependencies, devDependencies);\n Object.assign(apiPkg.scripts, scripts);\n await writePackageJson(apiDir, sortDeps(apiPkg));\n }\n\n // 6. Auto-wiring: connect all modules in the main app file\n await withSpinner('Conectando modulos automaticamente...', async () => {\n await generateWiring(config, apiDir);\n });\n\n // 7. Tailwind CSS setup\n if (config.tailwind) {\n await withSpinner('Configurando Tailwind CSS + paginas SaaS...', async () => {\n await setupTailwind(config, webDir);\n });\n }\n\n // 8. Docker compose\n if (config.database !== 'none' || config.redis || config.queue === 'rabbitmq' || config.minio) {\n await withSpinner('Gerando docker-compose.yml...', async () => {\n await generateDocker(config, projectDir, dockerServices);\n });\n }\n\n // 9. CI/CD\n if (config.cicd) {\n await withSpinner('Gerando CI/CD (GitHub Actions + Dockerfiles)...', async () => {\n await generateCICD(config, projectDir);\n });\n }\n\n // 10. Environment files\n await withSpinner('Gerando arquivos .env...', async () => {\n await generateEnv(config, apiDir, envEntries);\n });\n\n // 11. README\n await withSpinner('Gerando README.md...', async () => {\n await generateReadme(config, projectDir);\n });\n\n // 12. Liz - AI Agent config\n await withSpinner('Configurando Liz (AI Agent)...', async () => {\n await generateLiz(config, projectDir);\n });\n\n // 13. Install dependencies\n let installResult: { success: boolean; fallback?: string } = { success: false };\n try {\n await withSpinner(`Instalando dependencias (${config.runtime})...`, async () => {\n installResult = await installDependencies(projectDir, config.runtime);\n });\n if (installResult.fallback) {\n logger.warn(`${config.runtime} nao encontrado. Dependencias instaladas com ${installResult.fallback}.`);\n }\n } catch {\n logger.warn(`Nao foi possivel instalar dependencias automaticamente.`);\n logger.info(`Rode manualmente: cd ${config.projectName} && ${config.runtime} install`);\n }\n\n // 14. Git init\n try {\n await withSpinner('Inicializando repositorio git...', async () => {\n await initGit(projectDir);\n });\n } catch {\n logger.warn('Git nao encontrado. Inicialize manualmente com: git init');\n }\n\n // 15. Print success & next steps\n printNextSteps(config, installResult.success);\n}\n\nfunction printNextSteps(config: ProjectConfig, depsInstalled = true): void {\n const runCmd = getRunCommand(config.runtime);\n const hasDocker = config.database !== 'none' || config.redis || config.queue === 'rabbitmq' || config.minio;\n\n const authMethods = [\n config.auth.jwt && 'JWT',\n config.auth.magicLink && 'Magic Link',\n config.auth.googleOAuth && 'Google OAuth',\n ].filter(Boolean);\n\n const integrations = Object.entries(config.integrations)\n .filter(([, v]) => v)\n .map(([k]) => k);\n\n console.log(\n chalk.bold.green(`\n ╔═══════════════════════════════════════════════════╗\n ║ ║\n ║ Projeto \"${config.projectName}\" criado! ║\n ║ Tudo configurado pela Liz ║\n ║ ║\n ╚═══════════════════════════════════════════════════╝\n`)\n );\n\n console.log(chalk.bold.white(' O que a Liz configurou pra voce:\\n'));\n\n console.log(chalk.green(' + ') + chalk.white(`Frontend ${chalk.cyan(config.frontend)} pronto em apps/web/`));\n console.log(chalk.green(' + ') + chalk.white(`Backend ${chalk.cyan(config.backend)} pronto em apps/api/`));\n\n if (config.database !== 'none') {\n console.log(chalk.green(' + ') + chalk.white(`Banco ${chalk.cyan(config.database)} configurado`));\n }\n if (authMethods.length > 0) {\n console.log(chalk.green(' + ') + chalk.white(`Autenticacao: ${chalk.cyan(authMethods.join(', '))}`));\n }\n if (config.rbac) {\n console.log(chalk.green(' + ') + chalk.white(`RBAC com roles e permissoes (CASL)`));\n }\n if (config.organizations) {\n console.log(chalk.green(' + ') + chalk.white(`Organizations/Workspaces com convites`));\n }\n if (config.stripeBilling) {\n console.log(chalk.green(' + ') + chalk.white(`Stripe Billing com planos e assinaturas`));\n }\n if (config.zod) {\n console.log(chalk.green(' + ') + chalk.white(`Zod validation para input seguro`));\n }\n if (config.rateLimiting) {\n console.log(chalk.green(' + ') + chalk.white(`Rate Limiting para protecao da API`));\n }\n if (config.logging) {\n console.log(chalk.green(' + ') + chalk.white(`Pino logging estruturado`));\n }\n if (config.swagger) {\n console.log(chalk.green(' + ') + chalk.white(`Swagger/OpenAPI docs em /api/docs`));\n }\n if (config.redis) {\n console.log(chalk.green(' + ') + chalk.white(`Redis configurado`));\n }\n if (config.queue !== 'none') {\n console.log(chalk.green(' + ') + chalk.white(`Filas ${chalk.cyan(config.queue)} com worker`));\n }\n if (config.smtp) {\n console.log(chalk.green(' + ') + chalk.white(`SMTP com servico de email`));\n }\n if (config.minio) {\n console.log(chalk.green(' + ') + chalk.white(`MinIO storage`));\n }\n if (config.multiTenant) {\n console.log(chalk.green(' + ') + chalk.white(`Multi-tenant com middleware`));\n }\n if (config.websockets) {\n console.log(chalk.green(' + ') + chalk.white(`WebSockets (Socket.IO) para tempo real`));\n }\n if (config.tailwind) {\n console.log(chalk.green(' + ') + chalk.white(`Tailwind CSS + paginas SaaS prontas`));\n }\n if (config.cicd) {\n console.log(chalk.green(' + ') + chalk.white(`CI/CD (GitHub Actions + Dockerfiles)`));\n }\n if (config.pm2) {\n console.log(chalk.green(' + ') + chalk.white(`PM2 com cluster mode`));\n }\n if (integrations.length > 0) {\n console.log(chalk.green(' + ') + chalk.white(`Integracoes: ${chalk.cyan(integrations.join(', '))}`));\n }\n console.log(chalk.green(' + ') + chalk.white(`Liz (AI Agent) configurada`));\n\n if (hasDocker) {\n console.log(chalk.green(' + ') + chalk.white(`Docker Compose com todos os servicos`));\n }\n\n console.log(chalk.bold.white('\\n Proximos passos:\\n'));\n\n let step = 1;\n console.log(chalk.white(` ${step}. ${chalk.cyan(`cd ${config.projectName}`)}`));\n step++;\n\n if (!depsInstalled) {\n console.log(chalk.white(` ${step}. ${chalk.cyan(`${config.runtime} install`)}`));\n step++;\n }\n\n if (hasDocker) {\n console.log(chalk.white(` ${step}. ${chalk.cyan('docker compose up -d')}`));\n console.log(chalk.gray(' Sobe banco, redis, minio, etc em containers'));\n step++;\n }\n\n if (config.usePrisma) {\n console.log(chalk.white(` ${step}. ${chalk.cyan('cd apps/api && npx prisma db push && cd ../..')}`));\n console.log(chalk.gray(' Cria as tabelas no banco de dados'));\n step++;\n }\n\n console.log(chalk.white(` ${step}. ${chalk.cyan(`${runCmd} dev`)}`));\n console.log(chalk.gray(' Inicia frontend e API em modo desenvolvimento'));\n\n console.log(chalk.bold.white('\\n URLs:\\n'));\n console.log(chalk.white(` Frontend: ${chalk.cyan('http://localhost:3000')}`));\n console.log(chalk.white(` API: ${chalk.cyan('http://localhost:3001')}`));\n console.log(chalk.white(` Health: ${chalk.cyan('http://localhost:3001/api/health')}`));\n if (config.swagger) {\n console.log(chalk.white(` Docs: ${chalk.cyan('http://localhost:3001/api/docs')}`));\n }\n if (config.usePrisma) {\n console.log(chalk.white(` DB Studio: ${chalk.cyan('npx prisma studio')} (na pasta apps/api)`));\n }\n if (config.queue === 'rabbitmq') {\n console.log(chalk.white(` RabbitMQ: ${chalk.cyan('http://localhost:15672')} (guest/guest)`));\n }\n if (config.minio) {\n console.log(chalk.white(` MinIO: ${chalk.cyan('http://localhost:9001')} (minioadmin/minioadmin)`));\n }\n\n if (config.pm2) {\n console.log(chalk.bold.white('\\n Producao com PM2:\\n'));\n console.log(chalk.white(` ${chalk.cyan(`${runCmd} build`)} && ${chalk.cyan('pm2 start ecosystem.config.cjs')}`));\n }\n\n console.log(chalk.gray(`\\n Precisa de ajuda? A Liz esta disponivel no seu editor.`));\n console.log(chalk.gray(` Documentacao: https://github.com/pablocarss/plazercli\\n`));\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { ensureDir, writeFile, copyFile, getTemplatePath } from '../helpers/filesystem.js';\nimport { renderTemplate } from '../helpers/template.js';\nimport { getRunCommand } from '../helpers/runtime.js';\n\nexport async function generateBase(config: ProjectConfig): Promise<void> {\n const { projectDir, projectName, projectDescription, runtime } = config;\n\n // Create root directories\n await ensureDir(projectDir);\n await ensureDir(path.join(projectDir, 'apps'));\n await ensureDir(path.join(projectDir, 'apps', 'api'));\n await ensureDir(path.join(projectDir, 'apps', 'web'));\n\n // Render root package.json\n const runCmd = getRunCommand(runtime);\n const packageJsonTemplate = getTemplatePath('base', 'root', 'package.json.ejs');\n const packageJsonContent = await renderTemplate(packageJsonTemplate, {\n projectName,\n projectDescription,\n runCmd,\n });\n await writeFile(path.join(projectDir, 'package.json'), packageJsonContent);\n\n // Copy static root files\n await copyFile(\n getTemplatePath('base', 'root', 'gitignore'),\n path.join(projectDir, '.gitignore')\n );\n await copyFile(\n getTemplatePath('base', 'root', 'editorconfig'),\n path.join(projectDir, '.editorconfig')\n );\n await copyFile(\n getTemplatePath('base', 'root', 'nvmrc'),\n path.join(projectDir, '.nvmrc')\n );\n\n // pnpm-workspace.yaml only for pnpm\n if (runtime === 'pnpm') {\n await copyFile(\n getTemplatePath('base', 'root', 'pnpm-workspace.yaml'),\n path.join(projectDir, 'pnpm-workspace.yaml')\n );\n }\n}\n","import ejs from 'ejs';\nimport { readFile, writeFile, getTemplatePath } from './filesystem.js';\nimport path from 'path';\n\nexport async function renderTemplate(\n templatePath: string,\n data: Record<string, unknown>\n): Promise<string> {\n const template = await readFile(templatePath);\n return ejs.render(template, data, { async: false });\n}\n\nexport async function renderTemplateToFile(\n templateRelativePath: string,\n destPath: string,\n data: Record<string, unknown>\n): Promise<void> {\n const templatePath = getTemplatePath(templateRelativePath);\n const rendered = await renderTemplate(templatePath, data);\n\n // Remove .ejs extension from destination if present\n const finalDest = destPath.endsWith('.ejs')\n ? destPath.slice(0, -4)\n : destPath;\n\n await writeFile(finalDest, rendered);\n}\n\nexport async function renderAndWrite(\n templateDir: string,\n destDir: string,\n fileName: string,\n data: Record<string, unknown>\n): Promise<void> {\n const templatePath = path.join(templateDir, `${fileName}.ejs`);\n const rendered = await renderTemplate(templatePath, data);\n await writeFile(path.join(destDir, fileName), rendered);\n}\n","import { execa } from 'execa';\nimport type { ProjectConfig } from '../types/config.js';\n\nexport function getInstallCommand(runtime: ProjectConfig['runtime']): [string, string[]] {\n switch (runtime) {\n case 'bun':\n return ['bun', ['install']];\n case 'pnpm':\n return ['pnpm', ['install']];\n case 'npm':\n return ['npm', ['install']];\n }\n}\n\nexport function getRunCommand(runtime: ProjectConfig['runtime']): string {\n switch (runtime) {\n case 'bun':\n return 'bun run';\n case 'pnpm':\n return 'pnpm run';\n case 'npm':\n return 'npm run';\n }\n}\n\nasync function isCommandAvailable(cmd: string): Promise<boolean> {\n try {\n await execa('which', [cmd]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function installDependencies(\n projectDir: string,\n runtime: ProjectConfig['runtime']\n): Promise<{ success: boolean; fallback?: string }> {\n const [cmd, args] = getInstallCommand(runtime);\n\n // Check if selected runtime is available\n if (await isCommandAvailable(cmd)) {\n await execa(cmd, args, { cwd: projectDir, stdio: 'pipe' });\n return { success: true };\n }\n\n // Try fallback runtimes\n const fallbacks: ProjectConfig['runtime'][] = ['npm', 'pnpm', 'bun'];\n for (const fb of fallbacks) {\n if (fb === runtime) continue;\n const [fbCmd, fbArgs] = getInstallCommand(fb);\n if (await isCommandAvailable(fbCmd)) {\n await execa(fbCmd, fbArgs, { cwd: projectDir, stdio: 'pipe' });\n return { success: true, fallback: fb };\n }\n }\n\n return { success: false };\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile, ensureDir } from '../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../installers/dependencyVersionMap.js';\n\nexport async function generateFrontend(config: ProjectConfig, webDir: string): Promise<void> {\n switch (config.frontend) {\n case 'nextjs':\n await generateNextjs(config, webDir);\n break;\n case 'react-vite':\n await generateReactVite(config, webDir);\n break;\n case 'vue':\n await generateVue(config, webDir);\n break;\n case 'angular':\n await generateAngular(config, webDir);\n break;\n }\n}\n\nasync function generateNextjs(config: ProjectConfig, webDir: string): Promise<void> {\n await ensureDir(path.join(webDir, 'src', 'app'));\n await ensureDir(path.join(webDir, 'public'));\n\n await writeFile(path.join(webDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/web`,\n version: '0.1.0',\n private: true,\n scripts: {\n dev: 'next dev',\n build: 'next build',\n start: 'next start',\n lint: 'next lint',\n },\n dependencies: {\n next: deps.next,\n react: deps.react,\n 'react-dom': deps['react-dom'],\n },\n devDependencies: {\n '@types/node': deps['@types/node'],\n '@types/react': deps['@types/react'],\n '@types/react-dom': deps['@types/react-dom'],\n typescript: deps.typescript,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2017',\n lib: ['dom', 'dom.iterable', 'esnext'],\n allowJs: true,\n skipLibCheck: true,\n strict: true,\n noEmit: true,\n esModuleInterop: true,\n module: 'esnext',\n moduleResolution: 'bundler',\n resolveJsonModule: true,\n isolatedModules: true,\n jsx: 'preserve',\n incremental: true,\n plugins: [{ name: 'next' }],\n paths: { '@/*': ['./src/*'] },\n },\n include: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],\n exclude: ['node_modules'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'next.config.ts'), `import type { NextConfig } from 'next';\n\nconst nextConfig: NextConfig = {};\n\nexport default nextConfig;\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'layout.tsx'), `import type { Metadata } from 'next';\nimport './globals.css';\n\nexport const metadata: Metadata = {\n title: '${config.projectName}',\n description: '${config.projectDescription}',\n};\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <html lang=\"pt-BR\">\n <body>{children}</body>\n </html>\n );\n}\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'page.tsx'), `export default function Home() {\n return (\n <main style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', fontFamily: 'system-ui' }}>\n <h1>${config.projectName}</h1>\n <p>${config.projectDescription}</p>\n <p style={{ marginTop: '2rem', color: '#666' }}>\n API rodando em <a href=\"http://localhost:3001\" style={{ color: '#0070f3' }}>http://localhost:3001</a>\n </p>\n </main>\n );\n}\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'globals.css'), `* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: system-ui, -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n\na {\n color: inherit;\n text-decoration: none;\n}\n`);\n}\n\nasync function generateReactVite(config: ProjectConfig, webDir: string): Promise<void> {\n await ensureDir(path.join(webDir, 'src'));\n await ensureDir(path.join(webDir, 'public'));\n\n await writeFile(path.join(webDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/web`,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n dev: 'vite',\n build: 'tsc -b && vite build',\n preview: 'vite preview',\n },\n dependencies: {\n react: deps.react,\n 'react-dom': deps['react-dom'],\n },\n devDependencies: {\n '@types/react': deps['@types/react'],\n '@types/react-dom': deps['@types/react-dom'],\n '@vitejs/plugin-react': '^4.3.0',\n typescript: deps.typescript,\n vite: deps.vite,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2020',\n useDefineForClassFields: true,\n lib: ['ES2020', 'DOM', 'DOM.Iterable'],\n module: 'ESNext',\n skipLibCheck: true,\n moduleResolution: 'bundler',\n allowImportingTsExtensions: true,\n isolatedModules: true,\n noEmit: true,\n jsx: 'react-jsx',\n strict: true,\n },\n include: ['src'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'vite.config.ts'), `import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\nexport default defineConfig({\n plugins: [react()],\n server: {\n port: 3000,\n },\n});\n`);\n\n await writeFile(path.join(webDir, 'index.html'), `<!doctype html>\n<html lang=\"pt-BR\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${config.projectName}</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"></script>\n </body>\n</html>\n`);\n\n await writeFile(path.join(webDir, 'src', 'main.tsx'), `import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\nimport './index.css';\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <App />\n </React.StrictMode>,\n);\n`);\n\n await writeFile(path.join(webDir, 'src', 'App.tsx'), `function App() {\n return (\n <main style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', fontFamily: 'system-ui' }}>\n <h1>${config.projectName}</h1>\n <p>${config.projectDescription}</p>\n <p style={{ marginTop: '2rem', color: '#666' }}>\n API rodando em <a href=\"http://localhost:3001\" style={{ color: '#0070f3' }}>http://localhost:3001</a>\n </p>\n </main>\n );\n}\n\nexport default App;\n`);\n\n await writeFile(path.join(webDir, 'src', 'index.css'), `* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: system-ui, -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n`);\n}\n\nasync function generateVue(config: ProjectConfig, webDir: string): Promise<void> {\n await ensureDir(path.join(webDir, 'src'));\n await ensureDir(path.join(webDir, 'public'));\n\n await writeFile(path.join(webDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/web`,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n dev: 'vite',\n build: 'vue-tsc -b && vite build',\n preview: 'vite preview',\n },\n dependencies: {\n vue: deps.vue,\n 'vue-router': deps['vue-router'],\n },\n devDependencies: {\n '@vitejs/plugin-vue': deps['@vitejs/plugin-vue'],\n typescript: deps.typescript,\n vite: deps.vite,\n 'vue-tsc': '^2.1.0',\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n lib: ['ES2020', 'DOM', 'DOM.Iterable'],\n skipLibCheck: true,\n moduleResolution: 'bundler',\n allowImportingTsExtensions: true,\n isolatedModules: true,\n noEmit: true,\n jsx: 'preserve',\n strict: true,\n },\n include: ['src/**/*.ts', 'src/**/*.vue'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'vite.config.ts'), `import { defineConfig } from 'vite';\nimport vue from '@vitejs/plugin-vue';\n\nexport default defineConfig({\n plugins: [vue()],\n server: {\n port: 3000,\n },\n});\n`);\n\n await writeFile(path.join(webDir, 'index.html'), `<!doctype html>\n<html lang=\"pt-BR\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${config.projectName}</title>\n </head>\n <body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/src/main.ts\"></script>\n </body>\n</html>\n`);\n\n await writeFile(path.join(webDir, 'src', 'main.ts'), `import { createApp } from 'vue';\nimport App from './App.vue';\nimport './style.css';\n\ncreateApp(App).mount('#app');\n`);\n\n await writeFile(path.join(webDir, 'src', 'App.vue'), `<template>\n <main class=\"container\">\n <h1>${config.projectName}</h1>\n <p>${config.projectDescription}</p>\n <p class=\"api-link\">\n API rodando em <a href=\"http://localhost:3001\">http://localhost:3001</a>\n </p>\n </main>\n</template>\n\n<style scoped>\n.container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n font-family: system-ui;\n}\n.api-link {\n margin-top: 2rem;\n color: #666;\n}\n.api-link a {\n color: #42b883;\n}\n</style>\n`);\n\n await writeFile(path.join(webDir, 'src', 'style.css'), `* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: system-ui, -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n`);\n\n await writeFile(path.join(webDir, 'env.d.ts'), `/// <reference types=\"vite/client\" />\n`);\n}\n\nasync function generateAngular(config: ProjectConfig, webDir: string): Promise<void> {\n await ensureDir(path.join(webDir, 'src', 'app'));\n\n await writeFile(path.join(webDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/web`,\n version: '0.1.0',\n private: true,\n scripts: {\n dev: 'ng serve --port 3000',\n build: 'ng build',\n lint: 'ng lint',\n },\n dependencies: {\n '@angular/animations': deps['@angular/core'],\n '@angular/common': deps['@angular/core'],\n '@angular/compiler': deps['@angular/core'],\n '@angular/core': deps['@angular/core'],\n '@angular/forms': deps['@angular/core'],\n '@angular/platform-browser': deps['@angular/core'],\n '@angular/platform-browser-dynamic': deps['@angular/core'],\n '@angular/router': deps['@angular/core'],\n rxjs: deps.rxjs,\n 'zone.js': '^0.15.0',\n },\n devDependencies: {\n '@angular/cli': deps['@angular/cli'],\n '@angular/compiler-cli': deps['@angular/core'],\n typescript: deps.typescript,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2022',\n module: 'ES2022',\n lib: ['ES2022', 'dom'],\n skipLibCheck: true,\n moduleResolution: 'bundler',\n strict: true,\n noEmit: false,\n declaration: false,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n outDir: './dist',\n },\n include: ['src/**/*.ts'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'angular.json'), JSON.stringify({\n $schema: './node_modules/@angular/cli/lib/config/schema.json',\n version: 1,\n newProjectRoot: 'projects',\n projects: {\n web: {\n projectType: 'application',\n root: '',\n sourceRoot: 'src',\n architect: {\n build: {\n builder: '@angular-devkit/build-angular:application',\n options: {\n outputPath: 'dist',\n index: 'src/index.html',\n browser: 'src/main.ts',\n tsConfig: 'tsconfig.json',\n },\n },\n serve: {\n builder: '@angular-devkit/build-angular:dev-server',\n configurations: {\n development: { buildTarget: 'web:build' },\n },\n defaultConfiguration: 'development',\n },\n },\n },\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(webDir, 'src', 'index.html'), `<!doctype html>\n<html lang=\"pt-BR\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${config.projectName}</title>\n </head>\n <body>\n <app-root></app-root>\n </body>\n</html>\n`);\n\n await writeFile(path.join(webDir, 'src', 'main.ts'), `import { bootstrapApplication } from '@angular/platform-browser';\nimport { AppComponent } from './app/app.component';\n\nbootstrapApplication(AppComponent).catch((err) => console.error(err));\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'app.component.ts'), `import { Component } from '@angular/core';\n\n@Component({\n selector: 'app-root',\n standalone: true,\n template: \\`\n <main style=\"display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; font-family: system-ui;\">\n <h1>${config.projectName}</h1>\n <p>${config.projectDescription}</p>\n <p style=\"margin-top: 2rem; color: #666;\">\n API rodando em <a href=\"http://localhost:3001\" style=\"color: #dd0031;\">http://localhost:3001</a>\n </p>\n </main>\n \\`,\n})\nexport class AppComponent {}\n`);\n\n await writeFile(path.join(webDir, 'src', 'styles.css'), `* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: system-ui, -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n`);\n}\n","export const dependencyVersionMap = {\n // Prisma\n 'prisma': '^6.3.0',\n '@prisma/client': '^6.3.0',\n\n // Mongoose\n 'mongoose': '^8.9.0',\n\n // Auth\n 'jsonwebtoken': '^9.0.2',\n '@types/jsonwebtoken': '^9.0.7',\n 'bcryptjs': '^2.4.3',\n '@types/bcryptjs': '^2.4.6',\n 'passport': '^0.7.0',\n 'passport-jwt': '^4.0.1',\n '@types/passport-jwt': '^4.0.1',\n 'passport-google-oauth20': '^2.0.0',\n '@types/passport-google-oauth20': '^2.0.16',\n '@nestjs/jwt': '^11.0.0',\n '@nestjs/passport': '^11.0.0',\n 'nanoid': '^5.0.9',\n\n // Queues\n 'bullmq': '^5.30.0',\n '@nestjs/bullmq': '^11.0.0',\n 'amqplib': '^0.10.5',\n '@types/amqplib': '^0.10.6',\n\n // Redis\n 'ioredis': '^5.4.0',\n\n // SMTP\n 'nodemailer': '^6.9.0',\n '@types/nodemailer': '^6.4.17',\n\n // Storage\n 'minio': '^8.0.0',\n\n // Integrations\n 'axios': '^1.7.0',\n 'stripe': '^17.4.0',\n 'mercadopago': '^2.0.0',\n\n // Express\n 'express': '^4.21.0',\n '@types/express': '^4.17.21',\n 'cors': '^2.8.5',\n '@types/cors': '^2.8.17',\n 'helmet': '^8.0.0',\n 'dotenv': '^16.4.0',\n\n // Fastify\n '@fastify/cors': '^10.0.0',\n '@fastify/helmet': '^12.0.0',\n 'fastify': '^5.0.0',\n\n // NestJS\n '@nestjs/common': '^11.0.0',\n '@nestjs/core': '^11.0.0',\n '@nestjs/platform-express': '^11.0.0',\n '@nestjs/config': '^4.0.0',\n '@nestjs/cli': '^11.0.0',\n 'reflect-metadata': '^0.2.2',\n 'rxjs': '^7.8.1',\n\n // Next.js\n 'next': '^15.0.0',\n 'react': '^19.0.0',\n 'react-dom': '^19.0.0',\n '@types/react': '^19.0.0',\n '@types/react-dom': '^19.0.0',\n\n // Vue\n 'vue': '^3.5.0',\n 'vue-router': '^4.5.0',\n '@vitejs/plugin-vue': '^5.0.0',\n\n // Angular\n '@angular/core': '^19.0.0',\n '@angular/cli': '^19.0.0',\n\n // Common\n 'typescript': '^5.7.0',\n 'vite': '^6.0.0',\n '@types/node': '^22.10.0',\n 'tsx': '^4.19.0',\n 'pm2': '^5.4.0',\n\n // ---- NEW: v1.1+ features ----\n\n // Zod (validation)\n 'zod': '^3.23.0',\n 'nestjs-zod': '^4.0.0',\n\n // Rate Limiting\n 'express-rate-limit': '^7.4.0',\n '@fastify/rate-limit': '^10.0.0',\n '@nestjs/throttler': '^6.0.0',\n\n // Logging (Pino)\n 'pino': '^9.5.0',\n 'pino-pretty': '^13.0.0',\n 'pino-http': '^10.3.0',\n 'nestjs-pino': '^4.0.0',\n\n // Swagger / OpenAPI\n '@nestjs/swagger': '^8.0.0',\n '@fastify/swagger': '^9.0.0',\n '@fastify/swagger-ui': '^5.0.0',\n 'swagger-jsdoc': '^6.2.0',\n '@types/swagger-jsdoc': '^6.0.4',\n 'swagger-ui-express': '^5.0.0',\n '@types/swagger-ui-express': '^4.1.7',\n\n // RBAC\n 'casl': '^6.7.0',\n '@casl/ability': '^6.7.0',\n '@casl/prisma': '^1.5.0',\n\n // WebSockets\n '@nestjs/websockets': '^11.0.0',\n '@nestjs/platform-socket.io': '^11.0.0',\n 'socket.io': '^4.8.0',\n 'socket.io-client': '^4.8.0',\n\n // Tailwind CSS\n 'tailwindcss': '^3.4.0',\n 'postcss': '^8.4.0',\n 'autoprefixer': '^10.4.0',\n\n // ESLint & Prettier\n 'eslint': '^9.15.0',\n 'prettier': '^3.4.0',\n '@typescript-eslint/eslint-plugin': '^8.0.0',\n '@typescript-eslint/parser': '^8.0.0',\n\n // i18n\n 'next-intl': '^3.25.0',\n 'vue-i18n': '^10.0.0',\n 'i18next': '^23.16.0',\n 'react-i18next': '^15.1.0',\n\n // Stripe Billing (same stripe package, just noting it)\n // uses 'stripe' above\n} as const;\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile, ensureDir } from '../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../installers/dependencyVersionMap.js';\n\nexport async function generateBackend(config: ProjectConfig, apiDir: string): Promise<void> {\n switch (config.backend) {\n case 'express':\n await generateExpress(config, apiDir);\n break;\n case 'fastify':\n await generateFastify(config, apiDir);\n break;\n case 'nestjs':\n await generateNestjs(config, apiDir);\n break;\n }\n}\n\nasync function generateExpress(config: ProjectConfig, apiDir: string): Promise<void> {\n await ensureDir(path.join(apiDir, 'src', 'routes'));\n await ensureDir(path.join(apiDir, 'src', 'middlewares'));\n await ensureDir(path.join(apiDir, 'src', 'config'));\n\n await writeFile(path.join(apiDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/api`,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n dev: 'tsx watch src/index.ts',\n build: 'tsc',\n start: 'node dist/index.js',\n lint: 'tsc --noEmit',\n },\n dependencies: {\n express: deps.express,\n cors: deps.cors,\n helmet: deps.helmet,\n dotenv: deps.dotenv,\n },\n devDependencies: {\n '@types/express': deps['@types/express'],\n '@types/cors': deps['@types/cors'],\n '@types/node': deps['@types/node'],\n typescript: deps.typescript,\n tsx: deps.tsx,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n esModuleInterop: true,\n strict: true,\n outDir: 'dist',\n rootDir: 'src',\n skipLibCheck: true,\n declaration: true,\n },\n include: ['src/**/*'],\n exclude: ['node_modules', 'dist'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'src', 'config', 'index.ts'), `import 'dotenv/config';\n\nexport const config = {\n port: Number(process.env.PORT) || 3001,\n nodeEnv: process.env.NODE_ENV || 'development',\n corsOrigin: process.env.CORS_ORIGIN || 'http://localhost:3000',\n};\n`);\n\n await writeFile(path.join(apiDir, 'src', 'app.ts'), `import express from 'express';\nimport cors from 'cors';\nimport helmet from 'helmet';\nimport { config } from './config/index.js';\nimport { router } from './routes/index.js';\nimport { errorHandler } from './middlewares/errorHandler.js';\n\nconst app = express();\n\napp.use(helmet());\napp.use(cors({ origin: config.corsOrigin }));\napp.use(express.json());\n\napp.use('/api', router);\n\napp.use(errorHandler);\n\nexport { app };\n`);\n\n await writeFile(path.join(apiDir, 'src', 'index.ts'), `import { app } from './app.js';\nimport { config } from './config/index.js';\n\napp.listen(config.port, () => {\n console.log(\\`🚀 API rodando em http://localhost:\\${config.port}\\`);\n});\n`);\n\n await writeFile(path.join(apiDir, 'src', 'routes', 'index.ts'), `import { Router } from 'express';\n\nconst router = Router();\n\nrouter.get('/health', (_req, res) => {\n res.json({ status: 'ok', timestamp: new Date().toISOString() });\n});\n\nexport { router };\n`);\n\n await writeFile(path.join(apiDir, 'src', 'middlewares', 'errorHandler.ts'), `import type { Request, Response, NextFunction } from 'express';\n\nexport function errorHandler(err: Error, _req: Request, res: Response, _next: NextFunction) {\n console.error(err.stack);\n res.status(500).json({\n error: 'Internal Server Error',\n message: process.env.NODE_ENV === 'development' ? err.message : undefined,\n });\n}\n`);\n}\n\nasync function generateFastify(config: ProjectConfig, apiDir: string): Promise<void> {\n await ensureDir(path.join(apiDir, 'src', 'routes'));\n await ensureDir(path.join(apiDir, 'src', 'plugins'));\n await ensureDir(path.join(apiDir, 'src', 'config'));\n\n await writeFile(path.join(apiDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/api`,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n dev: 'tsx watch src/index.ts',\n build: 'tsc',\n start: 'node dist/index.js',\n lint: 'tsc --noEmit',\n },\n dependencies: {\n fastify: deps.fastify,\n '@fastify/cors': deps['@fastify/cors'],\n '@fastify/helmet': deps['@fastify/helmet'],\n dotenv: deps.dotenv,\n },\n devDependencies: {\n '@types/node': deps['@types/node'],\n typescript: deps.typescript,\n tsx: deps.tsx,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n esModuleInterop: true,\n strict: true,\n outDir: 'dist',\n rootDir: 'src',\n skipLibCheck: true,\n declaration: true,\n },\n include: ['src/**/*'],\n exclude: ['node_modules', 'dist'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'src', 'config', 'index.ts'), `import 'dotenv/config';\n\nexport const config = {\n port: Number(process.env.PORT) || 3001,\n host: process.env.HOST || '0.0.0.0',\n nodeEnv: process.env.NODE_ENV || 'development',\n corsOrigin: process.env.CORS_ORIGIN || 'http://localhost:3000',\n};\n`);\n\n await writeFile(path.join(apiDir, 'src', 'app.ts'), `import Fastify from 'fastify';\nimport cors from '@fastify/cors';\nimport helmet from '@fastify/helmet';\nimport { config } from './config/index.js';\nimport { registerRoutes } from './routes/index.js';\n\nexport async function buildApp() {\n const app = Fastify({\n logger: config.nodeEnv === 'development',\n });\n\n await app.register(helmet);\n await app.register(cors, { origin: config.corsOrigin });\n\n registerRoutes(app);\n\n return app;\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'index.ts'), `import { buildApp } from './app.js';\nimport { config } from './config/index.js';\n\nasync function start() {\n const app = await buildApp();\n\n await app.listen({ port: config.port, host: config.host });\n console.log(\\`🚀 API rodando em http://localhost:\\${config.port}\\`);\n}\n\nstart().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n`);\n\n await writeFile(path.join(apiDir, 'src', 'routes', 'index.ts'), `import type { FastifyInstance } from 'fastify';\n\nexport function registerRoutes(app: FastifyInstance) {\n app.get('/api/health', async () => {\n return { status: 'ok', timestamp: new Date().toISOString() };\n });\n}\n`);\n}\n\nasync function generateNestjs(config: ProjectConfig, apiDir: string): Promise<void> {\n await ensureDir(path.join(apiDir, 'src'));\n\n await writeFile(path.join(apiDir, 'package.json'), JSON.stringify({\n name: `@${config.projectName}/api`,\n version: '0.1.0',\n private: true,\n scripts: {\n dev: 'nest start --watch',\n build: 'nest build',\n start: 'node dist/main.js',\n 'start:prod': 'node dist/main.js',\n lint: 'tsc --noEmit',\n },\n dependencies: {\n '@nestjs/common': deps['@nestjs/common'],\n '@nestjs/core': deps['@nestjs/core'],\n '@nestjs/platform-express': deps['@nestjs/platform-express'],\n '@nestjs/config': deps['@nestjs/config'],\n 'reflect-metadata': deps['reflect-metadata'],\n rxjs: deps.rxjs,\n },\n devDependencies: {\n '@nestjs/cli': deps['@nestjs/cli'],\n '@types/node': deps['@types/node'],\n typescript: deps.typescript,\n },\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'tsconfig.json'), JSON.stringify({\n compilerOptions: {\n module: 'commonjs',\n declaration: true,\n removeComments: true,\n emitDecoratorMetadata: true,\n experimentalDecorators: true,\n allowSyntheticDefaultImports: true,\n target: 'ES2021',\n sourceMap: true,\n outDir: './dist',\n rootDir: './src',\n strict: true,\n skipLibCheck: true,\n },\n include: ['src/**/*'],\n exclude: ['node_modules', 'dist'],\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'nest-cli.json'), JSON.stringify({\n $schema: 'https://json.schemastore.org/nest-cli',\n collection: '@nestjs/schematics',\n sourceRoot: 'src',\n }, null, 2) + '\\n');\n\n await writeFile(path.join(apiDir, 'src', 'main.ts'), `import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n const app = await NestFactory.create(AppModule);\n app.enableCors({ origin: process.env.CORS_ORIGIN || 'http://localhost:3000' });\n app.setGlobalPrefix('api');\n\n const port = process.env.PORT || 3001;\n await app.listen(port);\n console.log(\\`🚀 API rodando em http://localhost:\\${port}\\`);\n}\n\nbootstrap();\n`);\n\n await writeFile(path.join(apiDir, 'src', 'app.module.ts'), `import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n imports: [\n ConfigModule.forRoot({ isGlobal: true }),\n ],\n controllers: [AppController],\n providers: [AppService],\n})\nexport class AppModule {}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'app.controller.ts'), `import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n constructor(private readonly appService: AppService) {}\n\n @Get('health')\n getHealth() {\n return this.appService.getHealth();\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'app.service.ts'), `import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n getHealth() {\n return { status: 'ok', timestamp: new Date().toISOString() };\n }\n}\n`);\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile } from '../helpers/filesystem.js';\n\nexport async function generateDocker(\n config: ProjectConfig,\n projectDir: string,\n extraServices: string[]\n): Promise<void> {\n const services: string[] = [];\n\n // Database services\n if (config.database === 'postgresql') {\n services.push(` postgres:\n image: postgres:16-alpine\n container_name: ${config.projectName}-postgres\n restart: unless-stopped\n environment:\n POSTGRES_USER: postgres\n POSTGRES_PASSWORD: postgres\n POSTGRES_DB: ${config.projectName.replace(/-/g, '_')}\n ports:\n - \"5432:5432\"\n volumes:\n - postgres_data:/var/lib/postgresql/data`);\n }\n\n if (config.database === 'mysql') {\n services.push(` mysql:\n image: mysql:8\n container_name: ${config.projectName}-mysql\n restart: unless-stopped\n environment:\n MYSQL_ROOT_PASSWORD: root\n MYSQL_DATABASE: ${config.projectName.replace(/-/g, '_')}\n MYSQL_USER: user\n MYSQL_PASSWORD: password\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql`);\n }\n\n if (config.database === 'mongodb') {\n services.push(` mongodb:\n image: mongo:7\n container_name: ${config.projectName}-mongodb\n restart: unless-stopped\n environment:\n MONGO_INITDB_ROOT_USERNAME: root\n MONGO_INITDB_ROOT_PASSWORD: root\n MONGO_INITDB_DATABASE: ${config.projectName.replace(/-/g, '_')}\n ports:\n - \"27017:27017\"\n volumes:\n - mongodb_data:/data/db`);\n }\n\n // Redis\n if (config.redis) {\n services.push(` redis:\n image: redis:7-alpine\n container_name: ${config.projectName}-redis\n restart: unless-stopped\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data`);\n }\n\n // RabbitMQ\n if (config.queue === 'rabbitmq') {\n services.push(` rabbitmq:\n image: rabbitmq:3-management-alpine\n container_name: ${config.projectName}-rabbitmq\n restart: unless-stopped\n environment:\n RABBITMQ_DEFAULT_USER: guest\n RABBITMQ_DEFAULT_PASS: guest\n ports:\n - \"5672:5672\"\n - \"15672:15672\"\n volumes:\n - rabbitmq_data:/var/lib/rabbitmq`);\n }\n\n // MinIO\n if (config.minio) {\n services.push(` minio:\n image: minio/minio\n container_name: ${config.projectName}-minio\n restart: unless-stopped\n command: server /data --console-address \":9001\"\n environment:\n MINIO_ROOT_USER: minioadmin\n MINIO_ROOT_PASSWORD: minioadmin\n ports:\n - \"9000:9000\"\n - \"9001:9001\"\n volumes:\n - minio_data:/data`);\n }\n\n // Extra services from installers\n services.push(...extraServices);\n\n // Volumes\n const volumes: string[] = [];\n if (config.database === 'postgresql') volumes.push(' postgres_data:');\n if (config.database === 'mysql') volumes.push(' mysql_data:');\n if (config.database === 'mongodb') volumes.push(' mongodb_data:');\n if (config.redis) volumes.push(' redis_data:');\n if (config.queue === 'rabbitmq') volumes.push(' rabbitmq_data:');\n if (config.minio) volumes.push(' minio_data:');\n\n const content = `services:\n${services.join('\\n\\n')}\n\nvolumes:\n${volumes.join('\\n')}\n`;\n\n await writeFile(path.join(projectDir, 'docker-compose.yml'), content);\n}\n","import path from 'path';\nimport type { ProjectConfig, EnvEntry } from '../types/config.js';\nimport { writeFile } from '../helpers/filesystem.js';\n\nexport async function generateEnv(\n config: ProjectConfig,\n apiDir: string,\n envEntries: EnvEntry[]\n): Promise<void> {\n // Add base entries\n const baseEntries: EnvEntry[] = [\n { key: 'NODE_ENV', value: 'development', category: 'App', comment: 'Ambiente' },\n { key: 'PORT', value: '3001', category: 'App' },\n ];\n\n // Database entries\n if (config.database === 'postgresql') {\n baseEntries.push({\n key: 'DATABASE_URL',\n value: `postgresql://postgres:postgres@localhost:5432/${config.projectName.replace(/-/g, '_')}`,\n category: 'Database',\n });\n } else if (config.database === 'mysql') {\n baseEntries.push({\n key: 'DATABASE_URL',\n value: `mysql://user:password@localhost:3306/${config.projectName.replace(/-/g, '_')}`,\n category: 'Database',\n });\n } else if (config.database === 'mongodb') {\n baseEntries.push({\n key: 'MONGODB_URI',\n value: `mongodb://root:root@localhost:27017/${config.projectName.replace(/-/g, '_')}?authSource=admin`,\n category: 'Database',\n });\n }\n\n const allEntries = [...baseEntries, ...envEntries];\n\n // Group by category\n const categories = new Map<string, EnvEntry[]>();\n for (const entry of allEntries) {\n const cat = entry.category;\n if (!categories.has(cat)) categories.set(cat, []);\n categories.get(cat)!.push(entry);\n }\n\n // Build .env content\n const lines: string[] = [];\n for (const [category, entries] of categories) {\n lines.push(`# ${category}`);\n for (const entry of entries) {\n if (entry.comment) lines.push(`# ${entry.comment}`);\n lines.push(`${entry.key}=\"${entry.value}\"`);\n }\n lines.push('');\n }\n\n const envContent = lines.join('\\n');\n\n // Write .env and .env.example\n await writeFile(path.join(apiDir, '.env'), envContent);\n await writeFile(path.join(apiDir, '.env.example'), envContent);\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile } from '../helpers/filesystem.js';\nimport { getRunCommand } from '../helpers/runtime.js';\n\nexport async function generateReadme(config: ProjectConfig, projectDir: string): Promise<void> {\n const runCmd = getRunCommand(config.runtime);\n const hasDocker = config.database !== 'none' || config.redis || config.queue === 'rabbitmq' || config.minio;\n\n const authMethods = [\n config.auth.jwt && 'JWT',\n config.auth.magicLink && 'Magic Link',\n config.auth.googleOAuth && 'Google OAuth',\n ].filter(Boolean);\n\n const integrations = [\n config.integrations.viacep && 'ViaCEP',\n config.integrations.whatsapp && 'WhatsApp',\n config.integrations.stripe && 'Stripe',\n config.integrations.mercadoPago && 'Mercado Pago',\n config.integrations.abacatePay && 'AbacatePay',\n ].filter(Boolean);\n\n const saasFeatures = [\n config.rbac && 'RBAC (Roles & Permissions)',\n config.organizations && 'Organizations/Workspaces',\n config.stripeBilling && 'Stripe Billing',\n ].filter(Boolean);\n\n const apiFeatures = [\n config.zod && 'Zod Validation',\n config.rateLimiting && 'Rate Limiting',\n config.logging && 'Pino Logging',\n config.swagger && 'Swagger/OpenAPI',\n ].filter(Boolean);\n\n const infra = [\n config.redis && 'Redis',\n config.smtp && 'SMTP',\n config.minio && 'MinIO',\n config.pm2 && 'PM2',\n config.websockets && 'WebSockets (Socket.IO)',\n ].filter(Boolean);\n\n const extras = [\n config.tailwind && 'Tailwind CSS',\n config.cicd && 'CI/CD (GitHub Actions)',\n config.i18n && 'i18n',\n ].filter(Boolean);\n\n let content = `# ${config.projectName}\n\n${config.projectDescription}\n\n> Projeto gerado com [PlazerCLI](https://github.com/pablocarss/plazercli) + Liz AI Agent\n\n## Stack\n\n| Camada | Tecnologia |\n|--------|-----------|\n| Frontend | ${config.frontend} |\n| Backend | ${config.backend} |\n${config.database !== 'none' ? `| Banco de dados | ${config.database} ${config.usePrisma ? '(Prisma)' : '(Mongoose)'} |` : ''}\n${authMethods.length > 0 ? `| Autenticacao | ${authMethods.join(', ')} |` : ''}\n${saasFeatures.length > 0 ? `| SaaS | ${saasFeatures.join(', ')} |` : ''}\n${apiFeatures.length > 0 ? `| API | ${apiFeatures.join(', ')} |` : ''}\n${config.queue !== 'none' ? `| Filas | ${config.queue} |` : ''}\n${infra.length > 0 ? `| Infraestrutura | ${infra.join(', ')} |` : ''}\n${integrations.length > 0 ? `| Integracoes | ${integrations.join(', ')} |` : ''}\n${extras.length > 0 ? `| Extras | ${extras.join(', ')} |` : ''}\n| Runtime | ${config.runtime} |\n\n## Estrutura\n\n\\`\\`\\`\n${config.projectName}/\n├── apps/\n│ ├── api/ # Backend ${config.backend}\n│ │ ├── src/\n${config.usePrisma ? '│ │ │ ├── database/ # Prisma service\\n' : ''}${config.useMongoose ? '│ │ │ ├── database/ # Mongoose models\\n' : ''}${config.hasAnyAuth ? '│ │ │ ├── auth/ # Autenticacao\\n' : ''}${config.rbac ? '│ │ │ ├── rbac/ # Roles e permissoes (CASL)\\n' : ''}${config.organizations ? '│ │ │ ├── organizations/ # Workspaces e convites\\n' : ''}${config.stripeBilling ? '│ │ │ ├── billing/ # Stripe planos e assinaturas\\n' : ''}${config.redis || config.smtp || config.minio ? '│ │ │ ├── infra/ # Redis, Email, Storage\\n' : ''}${config.hasAnyQueue ? '│ │ │ ├── queue/ # Workers e jobs\\n' : ''}${config.websockets ? '│ │ │ ├── websockets/ # Socket.IO gateway\\n' : ''}${config.hasAnyIntegration ? '│ │ │ ├── integrations/ # APIs externas\\n' : ''}${config.multiTenant ? '│ │ │ ├── tenant/ # Multi-tenant\\n' : ''}${config.zod ? '│ │ │ ├── common/validation/ # Zod schemas\\n' : ''}│ │ │ ├── routes/\n│ │ │ └── config/\n${config.usePrisma ? '│ │ └── prisma/schema.prisma\\n' : ''}│ │ └── .env\n│ └── web/ # Frontend ${config.frontend}\n│ └── src/\n├── docker-compose.yml\n├── CLAUDE.md # Liz config (Claude Code)\n├── AGENTS.md # Liz config (geral)\n└── README.md\n\\`\\`\\`\n\n## Quick Start\n\n\\`\\`\\`bash\n# Pre-requisitos: Node.js >= 20, ${config.runtime}${hasDocker ? ', Docker' : ''}\n`;\n\n let step = 1;\n\n if (hasDocker) {\n content += `\n# ${step}. Subir infraestrutura\ndocker compose up -d\n`;\n step++;\n }\n\n if (config.usePrisma) {\n content += `\n# ${step}. Criar tabelas no banco\ncd apps/api && npx prisma db push && cd ../..\n`;\n step++;\n }\n\n content += `\n# ${step}. Iniciar em modo desenvolvimento\n${runCmd} dev\n\\`\\`\\`\n\nPronto! Frontend em **http://localhost:3000** e API em **http://localhost:3001**\n`;\n\n // Auth endpoints documentation\n if (config.hasAnyAuth) {\n content += `\n## Autenticacao\n\n### Endpoints\n`;\n if (config.auth.jwt) {\n content += `\n**JWT:**\n- \\`POST /api/auth/register\\` - Criar conta\n \\`\\`\\`json\n { \"email\": \"user@email.com\", \"password\": \"123456\", \"name\": \"Nome\" }\n \\`\\`\\`\n- \\`POST /api/auth/login\\` - Login (retorna access_token)\n \\`\\`\\`json\n { \"email\": \"user@email.com\", \"password\": \"123456\" }\n \\`\\`\\`\n- Header: \\`Authorization: Bearer <token>\\`\n`;\n }\n if (config.auth.magicLink) {\n content += `\n**Magic Link:**\n- \\`POST /api/auth/magic-link/send\\` - Enviar link por email\n \\`\\`\\`json\n { \"email\": \"user@email.com\" }\n \\`\\`\\`\n- \\`GET /api/auth/magic-link/verify?token=xxx\\` - Verificar token\n`;\n }\n if (config.auth.googleOAuth) {\n content += `\n**Google OAuth:**\n- \\`GET /api/auth/google\\` - Redireciona para login Google\n- \\`GET /api/auth/google/callback\\` - Callback (configurar no Google Console)\n`;\n }\n }\n\n // Integrations documentation\n if (config.hasAnyIntegration) {\n content += `\n## Integracoes\n`;\n if (config.integrations.viacep) {\n content += `\n### ViaCEP\nServico em \\`apps/api/src/integrations/viacep/\\`\n\\`\\`\\`typescript\nimport { fetchAddress } from './integrations/viacep/viacep.service';\nconst endereco = await fetchAddress('01001000');\n\\`\\`\\`\n`;\n }\n if (config.integrations.stripe) {\n content += `\n### Stripe\nConfigurar \\`STRIPE_SECRET_KEY\\` e \\`STRIPE_WEBHOOK_SECRET\\` no .env\n\\`\\`\\`typescript\nimport { createCheckoutSession } from './integrations/stripe/stripe.service';\n\\`\\`\\`\n`;\n }\n if (config.integrations.mercadoPago) {\n content += `\n### Mercado Pago\nConfigurar \\`MERCADOPAGO_ACCESS_TOKEN\\` no .env\n\\`\\`\\`typescript\nimport { createPreference } from './integrations/mercado-pago/mercado-pago.service';\n\\`\\`\\`\n`;\n }\n if (config.integrations.whatsapp) {\n content += `\n### WhatsApp\nConfigurar \\`WHATSAPP_API_TOKEN\\` e \\`WHATSAPP_PHONE_ID\\` no .env\n\\`\\`\\`typescript\nimport { sendMessage } from './integrations/whatsapp/whatsapp.service';\nawait sendMessage('5511999999999', 'Olá!');\n\\`\\`\\`\n`;\n }\n }\n\n // SaaS Features documentation\n if (config.rbac || config.organizations || config.stripeBilling) {\n content += `\n## Features SaaS\n`;\n if (config.rbac) {\n content += `\n### RBAC (Roles e Permissoes)\nSistema de controle de acesso baseado em roles usando CASL.\n- Roles: \\`ADMIN\\`, \\`USER\\`, \\`OWNER\\`\n- Guards/middleware integrados nas rotas\n- Arquivos em \\`apps/api/src/rbac/\\`\n\n\\`\\`\\`typescript\n// Exemplo: proteger uma rota\n${config.backend === 'nestjs' ? `@UseGuards(RolesGuard)\n@Roles('ADMIN')\n@Get('admin/users')\nfindAll() { ... }` : `// Middleware: requireRole('ADMIN')\nrouter.get('/admin/users', requireRole('ADMIN'), handler);`}\n\\`\\`\\`\n`;\n }\n if (config.organizations) {\n content += `\n### Organizations/Workspaces\nCRUD completo de organizacoes com sistema de convites.\n\n**Endpoints:**\n- \\`POST /api/organizations\\` - Criar organizacao\n- \\`GET /api/organizations\\` - Listar organizacoes do usuario\n- \\`POST /api/organizations/:id/invite\\` - Convidar membro\n- \\`POST /api/organizations/invites/:token/accept\\` - Aceitar convite\n- \\`DELETE /api/organizations/:id/members/:userId\\` - Remover membro\n`;\n }\n if (config.stripeBilling) {\n content += `\n### Stripe Billing\nPlanos de assinatura com checkout, portal e webhooks.\n\n**Planos configurados:**\n- Free (gratis)\n- Pro ($29/mes)\n- Enterprise ($99/mes)\n\n**Endpoints:**\n- \\`POST /api/billing/checkout\\` - Criar sessao de checkout\n- \\`POST /api/billing/portal\\` - Abrir portal do cliente\n- \\`POST /api/billing/webhook\\` - Webhook do Stripe\n\nConfigurar no .env: \\`STRIPE_SECRET_KEY\\`, \\`STRIPE_WEBHOOK_SECRET\\`\n`;\n }\n }\n\n // API Quality documentation\n if (config.zod || config.rateLimiting || config.logging || config.swagger) {\n content += `\n## API Quality\n`;\n if (config.zod) {\n content += `\n### Validacao (Zod)\nSchemas de validacao em \\`apps/api/src/common/validation/\\`\n\\`\\`\\`typescript\n// Schemas prontos: CreateUserSchema, LoginSchema, PaginationSchema, etc.\n\\`\\`\\`\n`;\n }\n if (config.rateLimiting) {\n content += `\n### Rate Limiting\nProtecao contra abuso configurada globalmente.\n${config.backend === 'nestjs' ? '- Default: 10 req/s (short), 100 req/60s (medium), 1000 req/hora (long)' : '- Default: 100 req/15min por IP'}\n`;\n }\n if (config.swagger) {\n content += `\n### Swagger/OpenAPI\nDocumentacao automatica da API em **http://localhost:3001/api/docs**\n`;\n }\n if (config.logging) {\n content += `\n### Logging (Pino)\nLogging estruturado com correlacao de request ID.\n- Formato JSON em producao, pretty-print em desenvolvimento\n`;\n }\n }\n\n // WebSockets documentation\n if (config.websockets) {\n content += `\n## WebSockets (Socket.IO)\n\nComunicacao em tempo real configurada.\n\n\\`\\`\\`typescript\n// Client-side\nimport { io } from 'socket.io-client';\nconst socket = io('http://localhost:3001');\n\nsocket.on('notification', (data) => {\n console.log('Recebido:', data);\n});\n\nsocket.emit('message', { room: 'general', content: 'Hello!' });\n\\`\\`\\`\n`;\n }\n\n // Environment variables\n content += `\n## Variaveis de Ambiente\n\nEdite \\`apps/api/.env\\` com suas credenciais:\n\n| Variavel | Descricao |\n|----------|----------|\n| \\`PORT\\` | Porta da API (default: 3001) |\n`;\n\n if (config.database === 'postgresql' || config.database === 'mysql') {\n content += `| \\`DATABASE_URL\\` | URL de conexao do banco |\n`;\n }\n if (config.database === 'mongodb') {\n content += `| \\`MONGODB_URI\\` | URL de conexao do MongoDB |\n`;\n }\n if (config.auth.jwt) {\n content += `| \\`JWT_SECRET\\` | **Alterar em producao!** Secret para tokens |\n`;\n }\n if (config.auth.googleOAuth) {\n content += `| \\`GOOGLE_CLIENT_ID\\` | ID do app no Google Console |\n| \\`GOOGLE_CLIENT_SECRET\\` | Secret do app no Google Console |\n`;\n }\n if (config.redis) {\n content += `| \\`REDIS_HOST\\` | Host do Redis (default: localhost) |\n`;\n }\n if (config.smtp) {\n content += `| \\`SMTP_HOST\\`, \\`SMTP_USER\\`, \\`SMTP_PASS\\` | Credenciais SMTP |\n`;\n }\n if (config.minio) {\n content += `| \\`MINIO_ACCESS_KEY\\`, \\`MINIO_SECRET_KEY\\` | Credenciais MinIO |\n`;\n }\n if (config.stripeBilling || config.integrations.stripe) {\n content += `| \\`STRIPE_SECRET_KEY\\` | Chave secreta do Stripe |\n`;\n }\n if (config.stripeBilling) {\n content += `| \\`STRIPE_WEBHOOK_SECRET\\` | Secret do webhook Stripe |\n`;\n }\n if (config.integrations.mercadoPago) {\n content += `| \\`MERCADOPAGO_ACCESS_TOKEN\\` | Token do Mercado Pago |\n`;\n }\n\n content += `\n## Scripts\n\n| Comando | Descricao |\n|---------|----------|\n| \\`${runCmd} dev\\` | Inicia todos os apps |\n| \\`${runCmd} build\\` | Build de producao |\n| \\`${runCmd} dev:api\\` | Inicia apenas a API |\n| \\`${runCmd} dev:web\\` | Inicia apenas o frontend |\n${config.usePrisma ? `| \\`cd apps/api && npx prisma studio\\` | Admin visual do banco |\\n| \\`cd apps/api && npx prisma db push\\` | Sync schema com banco |` : ''}\n${config.pm2 ? `| \\`pm2 start ecosystem.config.cjs\\` | Deploy com zero-downtime |` : ''}\n${hasDocker ? `| \\`docker compose up -d\\` | Subir infraestrutura |` : ''}\n\n## Liz - AI Agent\n\nEste projeto vem com a **Liz**, uma assistente de IA configurada para conhecer a arquitetura do projeto.\n\n- **Claude Code:** Liz carrega automaticamente via \\`CLAUDE.md\\`\n- **Cursor:** Regras em \\`.cursor/rules/liz.mdc\\`\n- **Outros:** Consulte \\`AGENTS.md\\` para contexto completo\n\n---\n\nGerado com [PlazerCLI](https://github.com/pablocarss/plazercli)\n`;\n\n await writeFile(path.join(projectDir, 'README.md'), content);\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile } from '../helpers/filesystem.js';\n\nexport async function generateWiring(config: ProjectConfig, apiDir: string): Promise<void> {\n switch (config.backend) {\n case 'nestjs':\n await wireNestjs(config, apiDir);\n break;\n case 'express':\n await wireExpress(config, apiDir);\n break;\n case 'fastify':\n await wireFastify(config, apiDir);\n break;\n }\n}\n\nasync function wireNestjs(config: ProjectConfig, apiDir: string): Promise<void> {\n const imports: string[] = [];\n const modules: string[] = [];\n\n imports.push(`import { Module } from '@nestjs/common';`);\n imports.push(`import { ConfigModule } from '@nestjs/config';`);\n imports.push(`import { AppController } from './app.controller';`);\n imports.push(`import { AppService } from './app.service';`);\n\n modules.push(`ConfigModule.forRoot({ isGlobal: true })`);\n\n if (config.usePrisma) {\n imports.push(`import { PrismaModule } from './database/prisma.module';`);\n modules.push('PrismaModule');\n }\n\n if (config.redis) {\n imports.push(`import { RedisModule } from './infra/redis/redis.module';`);\n modules.push('RedisModule');\n }\n\n if (config.smtp) {\n imports.push(`import { EmailModule } from './infra/email/email.module';`);\n modules.push('EmailModule');\n }\n\n if (config.minio) {\n imports.push(`import { StorageModule } from './infra/storage/storage.module';`);\n modules.push('StorageModule');\n }\n\n if (config.auth.jwt) {\n imports.push(`import { AuthModule } from './auth/auth.module';`);\n modules.push('AuthModule');\n }\n\n if (config.multiTenant) {\n imports.push(`import { TenantModule } from './tenant/tenant.module';`);\n modules.push('TenantModule');\n }\n\n if (config.queue === 'bullmq') {\n imports.push(`import { QueueModule } from './queue/queue.module';`);\n modules.push('QueueModule');\n }\n\n if (config.queue === 'rabbitmq') {\n imports.push(`import { RabbitMQModule } from './queue/rabbitmq.config';`);\n modules.push('RabbitMQModule');\n }\n\n // New v1.1+ modules\n if (config.rbac) {\n imports.push(`import { RbacModule } from './rbac/rbac.module';`);\n modules.push('RbacModule');\n }\n\n if (config.organizations) {\n imports.push(`import { OrganizationsModule } from './organizations/organizations.module';`);\n modules.push('OrganizationsModule');\n }\n\n if (config.stripeBilling) {\n imports.push(`import { BillingModule } from './billing/billing.module';`);\n modules.push('BillingModule');\n }\n\n if (config.rateLimiting) {\n imports.push(`import { ThrottleModule } from './common/throttle/throttle.module';`);\n modules.push('ThrottleModule');\n }\n\n if (config.logging) {\n imports.push(`import { LoggerModule } from './common/logger/logger.module';`);\n modules.push('LoggerModule');\n }\n\n if (config.websockets) {\n imports.push(`import { EventsModule } from './websockets/events.module';`);\n modules.push('EventsModule');\n }\n\n const content = `${imports.join('\\n')}\n\n@Module({\n imports: [\n ${modules.join(',\\n ')},\n ],\n controllers: [AppController],\n providers: [AppService],\n})\nexport class AppModule {}\n`;\n\n await writeFile(path.join(apiDir, 'src', 'app.module.ts'), content);\n\n // Wire swagger in main.ts if enabled\n if (config.swagger) {\n await writeFile(path.join(apiDir, 'src', 'main.ts'), `import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n${config.swagger ? `import { setupSwagger } from './common/swagger/swagger.config';` : ''}\n${config.logging ? `import { Logger } from 'nestjs-pino';` : ''}\n\nasync function bootstrap() {\n const app = await NestFactory.create(AppModule${config.logging ? ', { bufferLogs: true }' : ''});\n${config.logging ? ' app.useLogger(app.get(Logger));' : ''}\n app.enableCors({ origin: process.env.CORS_ORIGIN || 'http://localhost:3000' });\n app.setGlobalPrefix('api');\n${config.swagger ? ' setupSwagger(app);' : ''}\n\n const port = process.env.PORT || 3001;\n await app.listen(port);\n console.log(\\`API rodando em http://localhost:\\${port}\\`);\n${config.swagger ? ` console.log(\\`Docs em http://localhost:\\${port}/api/docs\\`);` : ''}\n}\n\nbootstrap();\n`);\n }\n}\n\nasync function wireExpress(config: ProjectConfig, apiDir: string): Promise<void> {\n const imports: string[] = [];\n const setupLines: string[] = [];\n const routeLines: string[] = [];\n const middlewareLines: string[] = [];\n\n imports.push(`import express from 'express';`);\n imports.push(`import cors from 'cors';`);\n imports.push(`import helmet from 'helmet';`);\n imports.push(`import { config } from './config/index.js';`);\n imports.push(`import { router } from './routes/index.js';`);\n imports.push(`import { errorHandler } from './middlewares/errorHandler.js';`);\n\n if (config.logging) {\n imports.push(`import { httpLogger } from './middlewares/logger.js';`);\n middlewareLines.push(`app.use(httpLogger);`);\n }\n\n if (config.rateLimiting) {\n imports.push(`import { globalLimiter } from './middlewares/rateLimiter.js';`);\n middlewareLines.push(`app.use(globalLimiter);`);\n }\n\n if (config.useMongoose) {\n imports.push(`import { connectDB } from './database/connection.js';`);\n setupLines.push(` await connectDB();`);\n }\n\n if (config.multiTenant) {\n imports.push(`import { tenantMiddleware } from './tenant/tenant.middleware.js';`);\n }\n\n if (config.auth.jwt) {\n imports.push(`import { authRouter } from './auth/auth.routes.js';`);\n }\n\n if (config.auth.magicLink) {\n imports.push(`import { magicLinkRouter } from './auth/magic-link.routes.js';`);\n }\n\n if (config.auth.googleOAuth) {\n imports.push(`import { googleRouter } from './auth/google.routes.js';`);\n }\n\n if (config.organizations) {\n imports.push(`import { organizationsRouter } from './organizations/organizations.routes.js';`);\n }\n\n if (config.stripeBilling) {\n imports.push(`import { billingRouter } from './billing/billing.routes.js';`);\n }\n\n if (config.swagger) {\n imports.push(`import { setupSwagger } from './config/swagger.js';`);\n }\n\n if (config.queue === 'rabbitmq') {\n imports.push(`import { connectRabbitMQ } from './queue/rabbitmq.js';`);\n setupLines.push(` await connectRabbitMQ();`);\n }\n\n if (config.minio) {\n imports.push(`import { initStorage } from './infra/storage/storage.js';`);\n setupLines.push(` await initStorage();`);\n }\n\n // Build middleware registration\n if (config.multiTenant) {\n routeLines.push(`app.use(tenantMiddleware);`);\n }\n if (config.auth.jwt) {\n routeLines.push(`app.use('/api/auth', authRouter);`);\n }\n if (config.auth.magicLink) {\n routeLines.push(`app.use('/api/auth/magic-link', magicLinkRouter);`);\n }\n if (config.auth.googleOAuth) {\n routeLines.push(`app.use('/api/auth/google', googleRouter);`);\n }\n if (config.organizations) {\n routeLines.push(`app.use('/api/organizations', organizationsRouter);`);\n }\n if (config.stripeBilling) {\n routeLines.push(`app.use('/api/billing', billingRouter);`);\n }\n\n const appContent = `${imports.join('\\n')}\n\nconst app = express();\n\napp.use(helmet());\napp.use(cors({ origin: config.corsOrigin }));\napp.use(express.json());\n${middlewareLines.length > 0 ? '\\n' + middlewareLines.join('\\n') : ''}\n\n${routeLines.length > 0 ? '// Rotas auto-configuradas\\n' + routeLines.join('\\n') + '\\n' : ''}\napp.use('/api', router);\n\n${config.swagger ? '// Swagger docs\\nsetupSwagger(app);\\n' : ''}\napp.use(errorHandler);\n\nexport { app };\n`;\n\n const indexContent = `import { app } from './app.js';\nimport { config } from './config/index.js';\n${config.websockets ? `import { createServer } from 'http';\\nimport { initSocket } from './websockets/socket.js';` : ''}\n\nasync function start() {\n${setupLines.length > 0 ? setupLines.join('\\n') + '\\n' : ''}\n${config.websockets ? ` const server = createServer(app);\n initSocket(server);\n server.listen(config.port, () => {\n console.log(\\`API rodando em http://localhost:\\${config.port}\\`);\n });` : ` app.listen(config.port, () => {\n console.log(\\`API rodando em http://localhost:\\${config.port}\\`);\n });`}\n}\n\nstart().catch((err) => {\n console.error('Erro ao iniciar:', err);\n process.exit(1);\n});\n`;\n\n await writeFile(path.join(apiDir, 'src', 'app.ts'), appContent);\n await writeFile(path.join(apiDir, 'src', 'index.ts'), indexContent);\n}\n\nasync function wireFastify(config: ProjectConfig, apiDir: string): Promise<void> {\n const imports: string[] = [];\n const pluginLines: string[] = [];\n const setupLines: string[] = [];\n\n imports.push(`import Fastify from 'fastify';`);\n imports.push(`import cors from '@fastify/cors';`);\n imports.push(`import helmet from '@fastify/helmet';`);\n imports.push(`import { config } from './config/index.js';`);\n imports.push(`import { registerRoutes } from './routes/index.js';`);\n\n if (config.rateLimiting) {\n imports.push(`import rateLimitPlugin from './plugins/rateLimiter.js';`);\n pluginLines.push(` await app.register(rateLimitPlugin);`);\n }\n\n if (config.swagger) {\n imports.push(`import swaggerPlugin from './plugins/swagger.js';`);\n pluginLines.push(` await app.register(swaggerPlugin);`);\n }\n\n if (config.useMongoose) {\n imports.push(`import { connectDB } from './database/connection.js';`);\n setupLines.push(` await connectDB();`);\n }\n\n if (config.multiTenant) {\n imports.push(`import tenantPlugin from './tenant/tenant.plugin.js';`);\n pluginLines.push(` await app.register(tenantPlugin);`);\n }\n\n if (config.auth.jwt) {\n imports.push(`import { authRoutes } from './auth/auth.routes.js';`);\n pluginLines.push(` await app.register(authRoutes);`);\n }\n\n if (config.auth.magicLink) {\n imports.push(`import { magicLinkRoutes } from './auth/magic-link.routes.js';`);\n pluginLines.push(` await app.register(magicLinkRoutes);`);\n }\n\n if (config.auth.googleOAuth) {\n imports.push(`import { googleAuthRoutes } from './auth/google.routes.js';`);\n pluginLines.push(` await app.register(googleAuthRoutes);`);\n }\n\n if (config.organizations) {\n imports.push(`import { organizationsRoutes } from './organizations/organizations.routes.js';`);\n pluginLines.push(` await app.register(organizationsRoutes);`);\n }\n\n if (config.stripeBilling) {\n imports.push(`import { billingRoutes } from './billing/billing.routes.js';`);\n pluginLines.push(` await app.register(billingRoutes);`);\n }\n\n if (config.queue === 'rabbitmq') {\n imports.push(`import { connectRabbitMQ } from './queue/rabbitmq.js';`);\n setupLines.push(` await connectRabbitMQ();`);\n }\n\n if (config.minio) {\n imports.push(`import { initStorage } from './infra/storage/storage.js';`);\n setupLines.push(` await initStorage();`);\n }\n\n const loggerConfig = config.logging\n ? `{\n transport: config.nodeEnv === 'development' ? { target: 'pino-pretty', options: { colorize: true } } : undefined,\n level: process.env.LOG_LEVEL || 'info',\n }`\n : `config.nodeEnv === 'development'`;\n\n const appContent = `${imports.join('\\n')}\n\nexport async function buildApp() {\n const app = Fastify({\n logger: ${loggerConfig},\n });\n\n await app.register(helmet);\n await app.register(cors, { origin: config.corsOrigin });\n\n${pluginLines.length > 0 ? ' // Plugins auto-configurados\\n' + pluginLines.join('\\n') + '\\n' : ''}\n registerRoutes(app);\n\n return app;\n}\n`;\n\n const indexContent = `import { buildApp } from './app.js';\nimport { config } from './config/index.js';\n${config.websockets ? `import { initSocket } from './websockets/socket.js';` : ''}\n\nasync function start() {\n${setupLines.length > 0 ? setupLines.join('\\n') + '\\n' : ''}\n const app = await buildApp();\n\n await app.listen({ port: config.port, host: config.host });\n console.log(\\`API rodando em http://localhost:\\${config.port}\\`);\n${config.websockets ? ' initSocket(app.server);' : ''}\n}\n\nstart().catch((err) => {\n console.error('Erro ao iniciar:', err);\n process.exit(1);\n});\n`;\n\n await writeFile(path.join(apiDir, 'src', 'app.ts'), appContent);\n await writeFile(path.join(apiDir, 'src', 'index.ts'), indexContent);\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile, ensureDir } from '../helpers/filesystem.js';\n\nexport async function generateLiz(config: ProjectConfig, projectDir: string): Promise<void> {\n // Generate AGENTS.md (Claude Code / Copilot identity)\n await generateAgentsMd(config, projectDir);\n\n // Generate .cursor/rules (Cursor AI rules)\n await generateCursorRules(config, projectDir);\n\n // Generate CLAUDE.md (Claude Code specific)\n await generateClaudeMd(config, projectDir);\n}\n\nasync function generateAgentsMd(config: ProjectConfig, projectDir: string): Promise<void> {\n const authMethods = [\n config.auth.jwt && 'JWT',\n config.auth.magicLink && 'Magic Link',\n config.auth.googleOAuth && 'Google OAuth',\n ].filter(Boolean);\n\n const integrations = [\n config.integrations.viacep && 'ViaCEP',\n config.integrations.whatsapp && 'WhatsApp',\n config.integrations.stripe && 'Stripe',\n config.integrations.mercadoPago && 'Mercado Pago',\n config.integrations.abacatePay && 'AbacatePay',\n ].filter(Boolean);\n\n const content = `# Liz - AI Development Agent\n\n## Identidade\n\nEu sou a **Liz**, a assistente de desenvolvimento do projeto **${config.projectName}**. Fui configurada pelo PlazerCLI para conhecer profundamente a arquitetura deste projeto e ajudar no desenvolvimento.\n\n## Stack do Projeto\n\n- **Estrutura:** Monorepo com workspaces\n- **Frontend:** ${config.frontend} (apps/web/)\n- **Backend:** ${config.backend} (apps/api/)\n- **Runtime:** ${config.runtime}\n${config.database !== 'none' ? `- **Banco de dados:** ${config.database} ${config.usePrisma ? '(Prisma ORM)' : '(Mongoose ODM)'}` : ''}\n${authMethods.length > 0 ? `- **Autenticação:** ${authMethods.join(', ')}` : ''}\n${config.rbac ? '- **RBAC:** Roles e permissões (CASL)' : ''}\n${config.organizations ? '- **Organizations:** Workspaces com convites' : ''}\n${config.stripeBilling ? '- **Billing:** Stripe (planos, assinaturas, webhooks)' : ''}\n${config.zod ? '- **Validação:** Zod schemas' : ''}\n${config.rateLimiting ? '- **Rate Limiting:** Proteção contra abuso' : ''}\n${config.logging ? '- **Logging:** Pino (estruturado com request ID)' : ''}\n${config.swagger ? '- **Docs:** Swagger/OpenAPI em /api/docs' : ''}\n${config.redis ? '- **Cache:** Redis (ioredis)' : ''}\n${config.queue !== 'none' ? `- **Filas:** ${config.queue}` : ''}\n${config.smtp ? '- **Email:** Nodemailer (SMTP)' : ''}\n${config.minio ? '- **Storage:** MinIO (S3-compatible)' : ''}\n${config.websockets ? '- **WebSockets:** Socket.IO (tempo real)' : ''}\n${config.multiTenant ? '- **Multi-tenant:** Sim (isolamento por header/subdomain)' : ''}\n${config.tailwind ? '- **CSS:** Tailwind CSS + páginas SaaS' : ''}\n${config.cicd ? '- **CI/CD:** GitHub Actions + Dockerfiles' : ''}\n${config.i18n ? '- **i18n:** Internacionalização (pt-BR, en)' : ''}\n${config.pm2 ? '- **Deploy:** PM2 (cluster mode, zero-downtime)' : ''}\n${integrations.length > 0 ? `- **Integrações:** ${integrations.join(', ')}` : ''}\n\n## Estrutura de Diretórios\n\n\\`\\`\\`\n${config.projectName}/\n├── apps/\n│ ├── api/ # Backend (${config.backend})\n│ │ ├── src/\n${config.usePrisma ? '│ │ │ ├── database/ # Prisma service e conexão\\n' : ''}${config.useMongoose ? '│ │ │ ├── database/ # Mongoose models e conexão\\n' : ''}${config.hasAnyAuth ? '│ │ │ ├── auth/ # Autenticação e guards\\n' : ''}${config.rbac ? '│ │ │ ├── rbac/ # Roles e permissões (CASL)\\n' : ''}${config.organizations ? '│ │ │ ├── organizations/ # Workspaces e convites\\n' : ''}${config.stripeBilling ? '│ │ │ ├── billing/ # Stripe planos e assinaturas\\n' : ''}${config.redis ? '│ │ │ ├── infra/redis/ # Redis service\\n' : ''}${config.smtp ? '│ │ │ ├── infra/email/ # Email service e templates\\n' : ''}${config.minio ? '│ │ │ ├── infra/storage/ # MinIO storage service\\n' : ''}${config.hasAnyQueue ? '│ │ │ ├── queue/ # Workers e processadores\\n' : ''}${config.websockets ? '│ │ │ ├── websockets/ # Socket.IO gateway\\n' : ''}${config.zod ? '│ │ │ ├── common/validation/ # Zod schemas\\n' : ''}${config.hasAnyIntegration ? '│ │ │ ├── integrations/ # Integrações externas\\n' : ''}${config.multiTenant ? '│ │ │ ├── tenant/ # Multi-tenant middleware\\n' : ''}│ │ │ ├── routes/ # Rotas da API\n│ │ │ ├── config/ # Configurações\n│ │ │ └── middlewares/ # Middlewares\n${config.usePrisma ? '│ │ └── prisma/ # Schema do banco\\n' : ''}│ │ └── .env # Variáveis de ambiente\n│ └── web/ # Frontend (${config.frontend})\n│ └── src/\n├── docker-compose.yml\n├── .env.example\n└── README.md\n\\`\\`\\`\n\n## Convenções\n\n### Código\n- TypeScript strict mode\n- ESM modules (import/export)\n- Async/await para operações assíncronas\n- Nomes em inglês para código, comentários podem ser em português\n\n### API\n- Prefixo \\`/api\\` em todas as rotas\n- Health check em \\`GET /api/health\\`\n${config.hasAnyAuth ? `- Rotas de auth em \\`/api/auth/*\\`` : ''}\n- Respostas JSON com status HTTP corretos\n\n### Banco de Dados\n${config.usePrisma ? `- Prisma como ORM\n- Schema em \\`apps/api/prisma/schema.prisma\\`\n- Rodar \\`npx prisma db push\\` após alterar schema\n- Rodar \\`npx prisma generate\\` após alterar models` : ''}\n${config.useMongoose ? `- Mongoose como ODM\n- Models em \\`apps/api/src/database/models/\\`\n- Conexão em \\`apps/api/src/database/connection.ts\\`` : ''}\n\n## Como me usar\n\nAo desenvolver, me peça para:\n- Criar novas features seguindo a arquitetura existente\n- Criar novos endpoints/rotas\n- Adicionar models ao banco de dados\n- Criar novos workers/jobs\n- Integrar novos serviços\n- Debugar erros com contexto do projeto\n- Escrever testes\n\nEu conheço toda a stack e vou seguir as convenções do projeto.\n\n---\n*Configurada por PlazerCLI - https://github.com/pablocarss/plazercli*\n`;\n\n await writeFile(path.join(projectDir, 'AGENTS.md'), content);\n}\n\nasync function generateCursorRules(config: ProjectConfig, projectDir: string): Promise<void> {\n await ensureDir(path.join(projectDir, '.cursor', 'rules'));\n\n const content = `# Liz - PlazerCLI AI Agent Rules\n\nYou are Liz, the AI development assistant for the \"${config.projectName}\" project.\n\n## Project Context\n- Monorepo with apps/api (${config.backend}) and apps/web (${config.frontend})\n- Runtime: ${config.runtime}\n${config.database !== 'none' ? `- Database: ${config.database} ${config.usePrisma ? 'with Prisma ORM' : 'with Mongoose ODM'}` : ''}\n${config.hasAnyAuth ? '- Authentication configured and wired' : ''}\n${config.rbac ? '- RBAC with CASL (roles: ADMIN, USER, OWNER)' : ''}\n${config.organizations ? '- Organizations/Workspaces with invites' : ''}\n${config.stripeBilling ? '- Stripe Billing (subscriptions, webhooks)' : ''}\n${config.zod ? '- Zod validation schemas' : ''}\n${config.rateLimiting ? '- Rate limiting configured' : ''}\n${config.logging ? '- Pino structured logging' : ''}\n${config.swagger ? '- Swagger/OpenAPI docs at /api/docs' : ''}\n${config.redis ? '- Redis for caching' : ''}\n${config.queue !== 'none' ? `- Queue system: ${config.queue}` : ''}\n${config.websockets ? '- WebSockets (Socket.IO)' : ''}\n${config.tailwind ? '- Tailwind CSS with SaaS pages' : ''}\n${config.cicd ? '- CI/CD (GitHub Actions + Dockerfiles)' : ''}\n${config.i18n ? '- i18n (pt-BR, en)' : ''}\n\n## Rules\n- Always use TypeScript with strict mode\n- Follow existing patterns in the codebase\n- Use ESM imports (import/export, .js extensions)\n- API routes must be prefixed with /api\n- Use the existing database service/ORM for all DB operations\n${config.usePrisma ? '- After schema changes, remind to run: npx prisma db push' : ''}\n${config.backend === 'nestjs' ? '- Follow NestJS patterns: modules, controllers, services, guards' : ''}\n${config.backend === 'express' ? '- Use Express Router for new route groups' : ''}\n${config.backend === 'fastify' ? '- Use Fastify plugins for new functionality' : ''}\n- Write clean, minimal code - no over-engineering\n- Handle errors properly with appropriate HTTP status codes\n`;\n\n await writeFile(path.join(projectDir, '.cursor', 'rules', 'liz.mdc'), content);\n}\n\nasync function generateClaudeMd(config: ProjectConfig, projectDir: string): Promise<void> {\n const content = `# CLAUDE.md - Liz Agent Configuration\n\nYou are **Liz**, the AI development assistant for **${config.projectName}**.\n\n## Project Overview\nThis is a fullstack monorepo generated by PlazerCLI.\n\n- \\`apps/api/\\` - Backend (${config.backend})\n- \\`apps/web/\\` - Frontend (${config.frontend})\n- Runtime: ${config.runtime}\n${config.database !== 'none' ? `- Database: ${config.database}` : ''}\n\n## Key Files\n${config.backend === 'nestjs' ? '- `apps/api/src/app.module.ts` - Main module (all features auto-imported)' : ''}\n${config.backend === 'express' ? '- `apps/api/src/app.ts` - Express app (all routes auto-registered)' : ''}\n${config.backend === 'fastify' ? '- `apps/api/src/app.ts` - Fastify app (all plugins auto-registered)' : ''}\n${config.usePrisma ? '- `apps/api/prisma/schema.prisma` - Database schema' : ''}\n${config.rbac ? '- `apps/api/src/rbac/` - RBAC roles, guards, abilities (CASL)' : ''}\n${config.organizations ? '- `apps/api/src/organizations/` - Organizations CRUD + invites' : ''}\n${config.stripeBilling ? '- `apps/api/src/billing/` - Stripe subscriptions + webhooks' : ''}\n${config.zod ? '- `apps/api/src/common/validation/` - Zod validation schemas' : ''}\n${config.swagger ? '- `http://localhost:3001/api/docs` - Swagger/OpenAPI docs' : ''}\n- \\`apps/api/.env\\` - Environment variables\n- \\`docker-compose.yml\\` - Infrastructure services\n\n## Commands\n- \\`${config.runtime} run dev\\` - Start all apps\n- \\`${config.runtime} run dev:api\\` - Start only API\n- \\`${config.runtime} run dev:web\\` - Start only frontend\n${config.usePrisma ? '- `cd apps/api && npx prisma db push` - Push schema to DB\\n- `cd apps/api && npx prisma studio` - Open DB admin' : ''}\n- \\`docker compose up -d\\` - Start infrastructure\n\n## Conventions\n- TypeScript strict, ESM modules\n- API prefix: /api\n- Follow existing patterns when creating new features\n`;\n\n await writeFile(path.join(projectDir, 'CLAUDE.md'), content);\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile, ensureDir } from '../helpers/filesystem.js';\n\nexport async function generateCICD(config: ProjectConfig, projectDir: string): Promise<void> {\n await ensureDir(path.join(projectDir, '.github', 'workflows'));\n\n // GitHub Actions CI workflow\n await writeFile(path.join(projectDir, '.github', 'workflows', 'ci.yml'), generateCIWorkflow(config));\n\n // Dockerfile for API\n await writeFile(path.join(projectDir, 'apps', 'api', 'Dockerfile'), generateApiDockerfile(config));\n\n // Dockerfile for Web (if not Next.js on Vercel)\n await writeFile(path.join(projectDir, 'apps', 'web', 'Dockerfile'), generateWebDockerfile(config));\n\n // .dockerignore\n await writeFile(path.join(projectDir, '.dockerignore'), `node_modules\ndist\n.git\n.env\n.env.local\n*.log\n.next\n.nuxt\n.output\ncoverage\n.turbo\n`);\n}\n\nfunction generateCIWorkflow(config: ProjectConfig): string {\n const installCmd = config.runtime === 'pnpm' ? 'pnpm install --frozen-lockfile' :\n config.runtime === 'bun' ? 'bun install --frozen-lockfile' : 'npm ci';\n const setupRuntime = config.runtime === 'pnpm' ? `\n - name: Setup pnpm\n uses: pnpm/action-setup@v4\n with:\n version: 9` : config.runtime === 'bun' ? `\n - name: Setup Bun\n uses: oven-sh/setup-bun@v2` : '';\n\n return `name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\njobs:\n lint-and-build:\n runs-on: ubuntu-latest\n\n strategy:\n matrix:\n node-version: [20.x]\n\n steps:\n - name: Checkout\n uses: actions/checkout@v4\n${setupRuntime}\n - name: Setup Node.js \\${{ matrix.node-version }}\n uses: actions/setup-node@v4\n with:\n node-version: \\${{ matrix.node-version }}\n cache: '${config.runtime === 'bun' ? 'bun' : config.runtime}'\n\n - name: Install dependencies\n run: ${installCmd}\n\n - name: Lint API\n run: cd apps/api && ${config.runtime} run lint\n continue-on-error: true\n\n - name: Build API\n run: cd apps/api && ${config.runtime} run build\n\n - name: Build Web\n run: cd apps/web && ${config.runtime} run build\n${config.usePrisma ? `\n - name: Validate Prisma Schema\n run: cd apps/api && npx prisma validate` : ''}\n\n docker-build:\n runs-on: ubuntu-latest\n needs: lint-and-build\n if: github.ref == 'refs/heads/main'\n\n steps:\n - name: Checkout\n uses: actions/checkout@v4\n\n - name: Set up Docker Buildx\n uses: docker/setup-buildx-action@v3\n\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: apps/api/Dockerfile\n push: false\n tags: \\${{ github.repository }}-api:latest\n cache-from: type=gha\n cache-to: type=gha,mode=max\n\n - name: Build Web image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: apps/web/Dockerfile\n push: false\n tags: \\${{ github.repository }}-web:latest\n cache-from: type=gha\n cache-to: type=gha,mode=max\n`;\n}\n\nfunction generateApiDockerfile(config: ProjectConfig): string {\n const installCmd = config.runtime === 'pnpm'\n ? 'RUN corepack enable && corepack prepare pnpm@latest --activate\\nCOPY pnpm-lock.yaml* ./\\nRUN pnpm install --frozen-lockfile --prod'\n : config.runtime === 'bun'\n ? 'COPY bun.lockb* ./\\nRUN bun install --frozen-lockfile --production'\n : 'COPY package-lock.json* ./\\nRUN npm ci --omit=dev';\n\n const buildInstall = config.runtime === 'pnpm'\n ? 'RUN pnpm install --frozen-lockfile'\n : config.runtime === 'bun'\n ? 'RUN bun install --frozen-lockfile'\n : 'RUN npm ci';\n\n return `# Build stage\nFROM node:20-alpine AS builder\nWORKDIR /app\n\nCOPY apps/api/package.json ./\n${buildInstall}\n\nCOPY apps/api/ ./\n${config.usePrisma ? 'RUN npx prisma generate\\n' : ''}RUN npm run build\n\n# Production stage\nFROM node:20-alpine AS runner\nWORKDIR /app\n\nENV NODE_ENV=production\n\nRUN addgroup --system --gid 1001 nodejs\nRUN adduser --system --uid 1001 api\n\nCOPY --from=builder /app/dist ./dist\nCOPY --from=builder /app/package.json ./\n${config.usePrisma ? 'COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma\\n' : ''}\n${installCmd}\n\nUSER api\nEXPOSE 3001\n\nCMD [\"node\", \"dist/index.js\"]\n`;\n}\n\nfunction generateWebDockerfile(config: ProjectConfig): string {\n if (config.frontend === 'nextjs') {\n return `# Build stage\nFROM node:20-alpine AS builder\nWORKDIR /app\n\nCOPY apps/web/package.json ./\nRUN npm ci\n\nCOPY apps/web/ ./\nRUN npm run build\n\n# Production stage\nFROM node:20-alpine AS runner\nWORKDIR /app\n\nENV NODE_ENV=production\n\nRUN addgroup --system --gid 1001 nodejs\nRUN adduser --system --uid 1001 nextjs\n\nCOPY --from=builder /app/public ./public\nCOPY --from=builder /app/.next/standalone ./\nCOPY --from=builder /app/.next/static ./.next/static\n\nUSER nextjs\nEXPOSE 3000\n\nENV PORT=3000\nCMD [\"node\", \"server.js\"]\n`;\n }\n\n return `# Build stage\nFROM node:20-alpine AS builder\nWORKDIR /app\n\nCOPY apps/web/package.json ./\nRUN npm ci\n\nCOPY apps/web/ ./\nRUN npm run build\n\n# Production stage\nFROM nginx:alpine AS runner\n\nCOPY --from=builder /app/dist /usr/share/nginx/html\n\nCOPY <<EOF /etc/nginx/conf.d/default.conf\nserver {\n listen 3000;\n server_name _;\n root /usr/share/nginx/html;\n index index.html;\n\n location / {\n try_files \\\\$uri \\\\$uri/ /index.html;\n }\n\n location /api {\n proxy_pass http://api:3001;\n proxy_http_version 1.1;\n proxy_set_header Upgrade \\\\$http_upgrade;\n proxy_set_header Connection 'upgrade';\n proxy_set_header Host \\\\$host;\n proxy_cache_bypass \\\\$http_upgrade;\n }\n}\nEOF\n\nEXPOSE 3000\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n`;\n}\n","import path from 'path';\nimport type { ProjectConfig } from '../types/config.js';\nimport { writeFile } from '../helpers/filesystem.js';\nimport { readPackageJson, writePackageJson, sortDeps } from '../helpers/packages.js';\nimport { dependencyVersionMap as deps } from '../installers/dependencyVersionMap.js';\n\nexport async function setupTailwind(config: ProjectConfig, webDir: string): Promise<void> {\n // Add tailwind dependencies to web package.json\n const pkg = await readPackageJson(webDir);\n if (!pkg.devDependencies) pkg.devDependencies = {};\n pkg.devDependencies['tailwindcss'] = deps.tailwindcss;\n pkg.devDependencies['postcss'] = deps.postcss;\n pkg.devDependencies['autoprefixer'] = deps.autoprefixer;\n await writePackageJson(webDir, sortDeps(pkg));\n\n // Tailwind config\n const contentPaths = config.frontend === 'nextjs'\n ? `'./src/**/*.{js,ts,jsx,tsx,mdx}'`\n : config.frontend === 'vue'\n ? `'./src/**/*.{vue,js,ts,jsx,tsx}'`\n : config.frontend === 'angular'\n ? `'./src/**/*.{html,ts}'`\n : `'./src/**/*.{js,ts,jsx,tsx}'`;\n\n await writeFile(path.join(webDir, 'tailwind.config.js'), `/** @type {import('tailwindcss').Config} */\nexport default {\n content: [${contentPaths}],\n darkMode: 'class',\n theme: {\n extend: {\n colors: {\n primary: {\n 50: '#eff6ff',\n 100: '#dbeafe',\n 200: '#bfdbfe',\n 300: '#93c5fd',\n 400: '#60a5fa',\n 500: '#3b82f6',\n 600: '#2563eb',\n 700: '#1d4ed8',\n 800: '#1e40af',\n 900: '#1e3a8a',\n 950: '#172554',\n },\n },\n fontFamily: {\n sans: ['Inter', 'system-ui', '-apple-system', 'sans-serif'],\n },\n },\n },\n plugins: [],\n};\n`);\n\n await writeFile(path.join(webDir, 'postcss.config.js'), `export default {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n};\n`);\n\n // Rewrite the main CSS file with Tailwind directives\n const cssPath = getCssPath(config, webDir);\n await writeFile(cssPath, getTailwindCSS());\n\n // Generate SaaS layout pages based on frontend framework\n await generateSaaSPages(config, webDir);\n}\n\nfunction getCssPath(config: ProjectConfig, webDir: string): string {\n switch (config.frontend) {\n case 'nextjs':\n return path.join(webDir, 'src', 'app', 'globals.css');\n case 'react-vite':\n return path.join(webDir, 'src', 'index.css');\n case 'vue':\n return path.join(webDir, 'src', 'style.css');\n case 'angular':\n return path.join(webDir, 'src', 'styles.css');\n }\n}\n\nfunction getTailwindCSS(): string {\n return `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 222.2 84% 4.9%;\n --muted: 210 40% 96.1%;\n --muted-foreground: 215.4 16.3% 46.9%;\n --border: 214.3 31.8% 91.4%;\n --ring: 221.2 83.2% 53.3%;\n }\n\n .dark {\n --background: 222.2 84% 4.9%;\n --foreground: 210 40% 98%;\n --muted: 217.2 32.6% 17.5%;\n --muted-foreground: 215 20.2% 65.1%;\n --border: 217.2 32.6% 17.5%;\n --ring: 224.3 76.3% 48%;\n }\n\n body {\n @apply bg-white text-gray-900 dark:bg-gray-950 dark:text-gray-100;\n font-family: 'Inter', system-ui, -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n }\n}\n\n@layer components {\n .btn-primary {\n @apply inline-flex items-center justify-center rounded-lg bg-primary-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed;\n }\n\n .btn-secondary {\n @apply inline-flex items-center justify-center rounded-lg border border-gray-300 bg-white px-4 py-2.5 text-sm font-semibold text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 transition-colors dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700;\n }\n\n .input {\n @apply block w-full rounded-lg border border-gray-300 bg-white px-3 py-2.5 text-sm text-gray-900 placeholder-gray-400 shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-500;\n }\n\n .card {\n @apply rounded-xl border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800;\n }\n}\n`;\n}\n\nasync function generateSaaSPages(config: ProjectConfig, webDir: string): Promise<void> {\n switch (config.frontend) {\n case 'nextjs':\n await generateNextjsSaaSPages(config, webDir);\n break;\n case 'react-vite':\n await generateReactSaaSPages(config, webDir);\n break;\n case 'vue':\n await generateVueSaaSPages(config, webDir);\n break;\n case 'angular':\n await generateAngularSaaSPages(config, webDir);\n break;\n }\n}\n\nasync function generateNextjsSaaSPages(config: ProjectConfig, webDir: string): Promise<void> {\n // Layout with sidebar\n await writeFile(path.join(webDir, 'src', 'app', 'layout.tsx'), `import type { Metadata } from 'next';\nimport './globals.css';\n\nexport const metadata: Metadata = {\n title: '${config.projectName}',\n description: '${config.projectDescription}',\n};\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <html lang=\"pt-BR\" suppressHydrationWarning>\n <body>{children}</body>\n </html>\n );\n}\n`);\n\n // Landing page\n await writeFile(path.join(webDir, 'src', 'app', 'page.tsx'), `import Link from 'next/link';\n\nexport default function Home() {\n return (\n <div className=\"min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-950 dark:to-gray-900\">\n {/* Navbar */}\n <nav className=\"border-b border-gray-200 bg-white/80 backdrop-blur-sm dark:border-gray-800 dark:bg-gray-950/80\">\n <div className=\"mx-auto flex max-w-7xl items-center justify-between px-6 py-4\">\n <span className=\"text-xl font-bold text-primary-600\">${config.projectName}</span>\n <div className=\"flex items-center gap-4\">\n <Link href=\"/login\" className=\"text-sm font-medium text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100\">\n Entrar\n </Link>\n <Link href=\"/register\" className=\"btn-primary\">\n Comecar gratis\n </Link>\n </div>\n </div>\n </nav>\n\n {/* Hero */}\n <main className=\"mx-auto max-w-7xl px-6 py-24 text-center\">\n <h1 className=\"text-5xl font-bold tracking-tight text-gray-900 sm:text-6xl dark:text-white\">\n ${config.projectDescription}\n </h1>\n <p className=\"mx-auto mt-6 max-w-2xl text-lg text-gray-600 dark:text-gray-400\">\n Plataforma completa para gerenciar seu negocio. Rapido, seguro e escalavel.\n </p>\n <div className=\"mt-10 flex items-center justify-center gap-4\">\n <Link href=\"/register\" className=\"btn-primary text-base px-8 py-3\">\n Comecar agora\n </Link>\n <Link href=\"/login\" className=\"btn-secondary text-base px-8 py-3\">\n Ja tenho conta\n </Link>\n </div>\n\n {/* Features */}\n <div className=\"mt-24 grid gap-8 sm:grid-cols-2 lg:grid-cols-3\">\n {[\n { title: 'Rapido', desc: 'Performance otimizada para a melhor experiencia do usuario' },\n { title: 'Seguro', desc: 'Autenticacao robusta e protecao de dados integrada' },\n { title: 'Escalavel', desc: 'Arquitetura pronta para crescer com seu negocio' },\n ].map((feature) => (\n <div key={feature.title} className=\"card text-left\">\n <h3 className=\"text-lg font-semibold text-gray-900 dark:text-white\">{feature.title}</h3>\n <p className=\"mt-2 text-gray-600 dark:text-gray-400\">{feature.desc}</p>\n </div>\n ))}\n </div>\n </main>\n\n {/* Footer */}\n <footer className=\"border-t border-gray-200 py-8 text-center text-sm text-gray-500 dark:border-gray-800\">\n &copy; {new Date().getFullYear()} ${config.projectName}. Todos os direitos reservados.\n </footer>\n </div>\n );\n}\n`);\n\n // Login page\n await writeFile(path.join(webDir, 'src', 'app', 'login', 'page.tsx'), `'use client';\n\nimport { useState } from 'react';\nimport Link from 'next/link';\n\nexport default function LoginPage() {\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n const res = await fetch('http://localhost:3001/api/auth/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password }),\n });\n const data = await res.json();\n if (data.access_token) {\n localStorage.setItem('token', data.access_token);\n window.location.href = '/dashboard';\n }\n };\n\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-gray-50 px-4 dark:bg-gray-950\">\n <div className=\"w-full max-w-md\">\n <div className=\"text-center mb-8\">\n <Link href=\"/\" className=\"text-2xl font-bold text-primary-600\">${config.projectName}</Link>\n <h1 className=\"mt-4 text-2xl font-bold text-gray-900 dark:text-white\">Entrar na sua conta</h1>\n </div>\n\n <form onSubmit={handleSubmit} className=\"card space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Email</label>\n <input type=\"email\" value={email} onChange={(e) => setEmail(e.target.value)} className=\"input\" placeholder=\"seu@email.com\" required />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Senha</label>\n <input type=\"password\" value={password} onChange={(e) => setPassword(e.target.value)} className=\"input\" placeholder=\"••••••••\" required />\n </div>\n <button type=\"submit\" className=\"btn-primary w-full\">Entrar</button>\n <p className=\"text-center text-sm text-gray-500\">\n Nao tem conta?{' '}\n <Link href=\"/register\" className=\"text-primary-600 hover:text-primary-700 font-medium\">Criar conta</Link>\n </p>\n </form>\n </div>\n </div>\n );\n}\n`);\n\n // Register page\n await writeFile(path.join(webDir, 'src', 'app', 'register', 'page.tsx'), `'use client';\n\nimport { useState } from 'react';\nimport Link from 'next/link';\n\nexport default function RegisterPage() {\n const [name, setName] = useState('');\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n const res = await fetch('http://localhost:3001/api/auth/register', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ name, email, password }),\n });\n const data = await res.json();\n if (data.access_token) {\n localStorage.setItem('token', data.access_token);\n window.location.href = '/dashboard';\n }\n };\n\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-gray-50 px-4 dark:bg-gray-950\">\n <div className=\"w-full max-w-md\">\n <div className=\"text-center mb-8\">\n <Link href=\"/\" className=\"text-2xl font-bold text-primary-600\">${config.projectName}</Link>\n <h1 className=\"mt-4 text-2xl font-bold text-gray-900 dark:text-white\">Criar sua conta</h1>\n </div>\n\n <form onSubmit={handleSubmit} className=\"card space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Nome</label>\n <input type=\"text\" value={name} onChange={(e) => setName(e.target.value)} className=\"input\" placeholder=\"Seu nome\" required />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Email</label>\n <input type=\"email\" value={email} onChange={(e) => setEmail(e.target.value)} className=\"input\" placeholder=\"seu@email.com\" required />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Senha</label>\n <input type=\"password\" value={password} onChange={(e) => setPassword(e.target.value)} className=\"input\" placeholder=\"••••••••\" minLength={6} required />\n </div>\n <button type=\"submit\" className=\"btn-primary w-full\">Criar conta</button>\n <p className=\"text-center text-sm text-gray-500\">\n Ja tem conta?{' '}\n <Link href=\"/login\" className=\"text-primary-600 hover:text-primary-700 font-medium\">Entrar</Link>\n </p>\n </form>\n </div>\n </div>\n );\n}\n`);\n\n // Dashboard page\n await writeFile(path.join(webDir, 'src', 'app', 'dashboard', 'page.tsx'), `'use client';\n\nimport Link from 'next/link';\n\nconst stats = [\n { name: 'Usuarios', value: '0', change: '+0%' },\n { name: 'Receita', value: 'R$ 0', change: '+0%' },\n { name: 'Pedidos', value: '0', change: '+0%' },\n { name: 'Conversao', value: '0%', change: '+0%' },\n];\n\nexport default function DashboardPage() {\n return (\n <div className=\"flex min-h-screen bg-gray-50 dark:bg-gray-950\">\n {/* Sidebar */}\n <aside className=\"hidden w-64 border-r border-gray-200 bg-white p-6 lg:block dark:border-gray-800 dark:bg-gray-900\">\n <Link href=\"/\" className=\"text-xl font-bold text-primary-600\">${config.projectName}</Link>\n <nav className=\"mt-8 space-y-1\">\n {[\n { name: 'Dashboard', href: '/dashboard', active: true },\n { name: 'Usuarios', href: '/dashboard/users', active: false },\n { name: 'Configuracoes', href: '/dashboard/settings', active: false },\n ].map((item) => (\n <Link key={item.name} href={item.href}\n className={\\`block rounded-lg px-3 py-2 text-sm font-medium transition-colors \\${\n item.active\n ? 'bg-primary-50 text-primary-700 dark:bg-primary-900/20 dark:text-primary-400'\n : 'text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800'\n }\\`}>\n {item.name}\n </Link>\n ))}\n </nav>\n </aside>\n\n {/* Main */}\n <main className=\"flex-1 p-8\">\n <div className=\"mb-8\">\n <h1 className=\"text-2xl font-bold text-gray-900 dark:text-white\">Dashboard</h1>\n <p className=\"mt-1 text-gray-500\">Visao geral do seu projeto.</p>\n </div>\n\n {/* Stats */}\n <div className=\"grid gap-6 sm:grid-cols-2 lg:grid-cols-4\">\n {stats.map((stat) => (\n <div key={stat.name} className=\"card\">\n <p className=\"text-sm font-medium text-gray-500 dark:text-gray-400\">{stat.name}</p>\n <p className=\"mt-1 text-3xl font-bold text-gray-900 dark:text-white\">{stat.value}</p>\n <p className=\"mt-1 text-sm text-green-600\">{stat.change}</p>\n </div>\n ))}\n </div>\n\n {/* Quick Actions */}\n <div className=\"mt-8 card\">\n <h2 className=\"text-lg font-semibold text-gray-900 dark:text-white\">Proximos passos</h2>\n <div className=\"mt-4 space-y-3\">\n <div className=\"flex items-center gap-3 rounded-lg border border-gray-200 p-4 dark:border-gray-700\">\n <div className=\"flex-1\">\n <p className=\"font-medium text-gray-900 dark:text-white\">Conectar banco de dados</p>\n <p className=\"text-sm text-gray-500\">Configure o .env com suas credenciais</p>\n </div>\n </div>\n <div className=\"flex items-center gap-3 rounded-lg border border-gray-200 p-4 dark:border-gray-700\">\n <div className=\"flex-1\">\n <p className=\"font-medium text-gray-900 dark:text-white\">API rodando</p>\n <p className=\"text-sm text-gray-500\">\n <a href=\"http://localhost:3001/api/health\" className=\"text-primary-600 hover:underline\" target=\"_blank\" rel=\"noreferrer\">\n http://localhost:3001/api/health\n </a>\n </p>\n </div>\n </div>\n </div>\n </div>\n </main>\n </div>\n );\n}\n`);\n\n // Settings page\n await writeFile(path.join(webDir, 'src', 'app', 'dashboard', 'settings', 'page.tsx'), `'use client';\n\nimport { useState } from 'react';\nimport Link from 'next/link';\n\nexport default function SettingsPage() {\n const [name, setName] = useState('');\n const [email, setEmail] = useState('');\n\n return (\n <div className=\"flex min-h-screen bg-gray-50 dark:bg-gray-950\">\n <aside className=\"hidden w-64 border-r border-gray-200 bg-white p-6 lg:block dark:border-gray-800 dark:bg-gray-900\">\n <Link href=\"/\" className=\"text-xl font-bold text-primary-600\">${config.projectName}</Link>\n <nav className=\"mt-8 space-y-1\">\n <Link href=\"/dashboard\" className=\"block rounded-lg px-3 py-2 text-sm font-medium text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800\">Dashboard</Link>\n <Link href=\"/dashboard/settings\" className=\"block rounded-lg px-3 py-2 text-sm font-medium bg-primary-50 text-primary-700 dark:bg-primary-900/20 dark:text-primary-400\">Configuracoes</Link>\n </nav>\n </aside>\n\n <main className=\"flex-1 p-8\">\n <h1 className=\"text-2xl font-bold text-gray-900 dark:text-white\">Configuracoes</h1>\n <p className=\"mt-1 text-gray-500 mb-8\">Gerencie suas informacoes pessoais.</p>\n\n <div className=\"card max-w-2xl space-y-6\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Nome</label>\n <input type=\"text\" value={name} onChange={(e) => setName(e.target.value)} className=\"input\" placeholder=\"Seu nome\" />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Email</label>\n <input type=\"email\" value={email} onChange={(e) => setEmail(e.target.value)} className=\"input\" placeholder=\"seu@email.com\" />\n </div>\n <div className=\"flex justify-end\">\n <button className=\"btn-primary\">Salvar alteracoes</button>\n </div>\n </div>\n </main>\n </div>\n );\n}\n`);\n}\n\nasync function generateReactSaaSPages(config: ProjectConfig, webDir: string): Promise<void> {\n await writeFile(path.join(webDir, 'src', 'App.tsx'), `import { BrowserRouter, Routes, Route } from 'react-router-dom';\nimport Home from './pages/Home';\nimport Login from './pages/Login';\nimport Register from './pages/Register';\nimport Dashboard from './pages/Dashboard';\n\nfunction App() {\n return (\n <BrowserRouter>\n <Routes>\n <Route path=\"/\" element={<Home />} />\n <Route path=\"/login\" element={<Login />} />\n <Route path=\"/register\" element={<Register />} />\n <Route path=\"/dashboard\" element={<Dashboard />} />\n </Routes>\n </BrowserRouter>\n );\n}\n\nexport default App;\n`);\n\n await writeFile(path.join(webDir, 'src', 'pages', 'Home.tsx'), `import { Link } from 'react-router-dom';\n\nexport default function Home() {\n return (\n <div className=\"min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-950 dark:to-gray-900\">\n <nav className=\"border-b border-gray-200 bg-white/80 backdrop-blur-sm dark:border-gray-800 dark:bg-gray-950/80\">\n <div className=\"mx-auto flex max-w-7xl items-center justify-between px-6 py-4\">\n <span className=\"text-xl font-bold text-primary-600\">${config.projectName}</span>\n <div className=\"flex items-center gap-4\">\n <Link to=\"/login\" className=\"text-sm font-medium text-gray-600 hover:text-gray-900 dark:text-gray-400\">Entrar</Link>\n <Link to=\"/register\" className=\"btn-primary\">Comecar gratis</Link>\n </div>\n </div>\n </nav>\n <main className=\"mx-auto max-w-7xl px-6 py-24 text-center\">\n <h1 className=\"text-5xl font-bold tracking-tight text-gray-900 dark:text-white\">${config.projectDescription}</h1>\n <p className=\"mx-auto mt-6 max-w-2xl text-lg text-gray-600 dark:text-gray-400\">Plataforma completa para gerenciar seu negocio.</p>\n <div className=\"mt-10 flex items-center justify-center gap-4\">\n <Link to=\"/register\" className=\"btn-primary text-base px-8 py-3\">Comecar agora</Link>\n <Link to=\"/login\" className=\"btn-secondary text-base px-8 py-3\">Ja tenho conta</Link>\n </div>\n </main>\n </div>\n );\n}\n`);\n\n await writeFile(path.join(webDir, 'src', 'pages', 'Login.tsx'), `import { useState } from 'react';\nimport { Link } from 'react-router-dom';\n\nexport default function Login() {\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n const res = await fetch('http://localhost:3001/api/auth/login', {\n method: 'POST', headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password }),\n });\n const data = await res.json();\n if (data.access_token) { localStorage.setItem('token', data.access_token); window.location.href = '/dashboard'; }\n };\n\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-gray-50 px-4 dark:bg-gray-950\">\n <div className=\"w-full max-w-md\">\n <div className=\"text-center mb-8\">\n <Link to=\"/\" className=\"text-2xl font-bold text-primary-600\">${config.projectName}</Link>\n <h1 className=\"mt-4 text-2xl font-bold text-gray-900 dark:text-white\">Entrar</h1>\n </div>\n <form onSubmit={handleSubmit} className=\"card space-y-4\">\n <div><label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Email</label><input type=\"email\" value={email} onChange={e => setEmail(e.target.value)} className=\"input\" required /></div>\n <div><label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Senha</label><input type=\"password\" value={password} onChange={e => setPassword(e.target.value)} className=\"input\" required /></div>\n <button type=\"submit\" className=\"btn-primary w-full\">Entrar</button>\n <p className=\"text-center text-sm text-gray-500\">Nao tem conta? <Link to=\"/register\" className=\"text-primary-600 font-medium\">Criar conta</Link></p>\n </form>\n </div>\n </div>\n );\n}\n`);\n\n await writeFile(path.join(webDir, 'src', 'pages', 'Register.tsx'), `import { useState } from 'react';\nimport { Link } from 'react-router-dom';\n\nexport default function Register() {\n const [name, setName] = useState('');\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n const res = await fetch('http://localhost:3001/api/auth/register', {\n method: 'POST', headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ name, email, password }),\n });\n const data = await res.json();\n if (data.access_token) { localStorage.setItem('token', data.access_token); window.location.href = '/dashboard'; }\n };\n\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-gray-50 px-4 dark:bg-gray-950\">\n <div className=\"w-full max-w-md\">\n <div className=\"text-center mb-8\">\n <Link to=\"/\" className=\"text-2xl font-bold text-primary-600\">${config.projectName}</Link>\n <h1 className=\"mt-4 text-2xl font-bold text-gray-900 dark:text-white\">Criar conta</h1>\n </div>\n <form onSubmit={handleSubmit} className=\"card space-y-4\">\n <div><label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Nome</label><input type=\"text\" value={name} onChange={e => setName(e.target.value)} className=\"input\" required /></div>\n <div><label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Email</label><input type=\"email\" value={email} onChange={e => setEmail(e.target.value)} className=\"input\" required /></div>\n <div><label className=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Senha</label><input type=\"password\" value={password} onChange={e => setPassword(e.target.value)} className=\"input\" minLength={6} required /></div>\n <button type=\"submit\" className=\"btn-primary w-full\">Criar conta</button>\n <p className=\"text-center text-sm text-gray-500\">Ja tem conta? <Link to=\"/login\" className=\"text-primary-600 font-medium\">Entrar</Link></p>\n </form>\n </div>\n </div>\n );\n}\n`);\n\n await writeFile(path.join(webDir, 'src', 'pages', 'Dashboard.tsx'), `import { Link } from 'react-router-dom';\n\nexport default function Dashboard() {\n return (\n <div className=\"flex min-h-screen bg-gray-50 dark:bg-gray-950\">\n <aside className=\"hidden w-64 border-r border-gray-200 bg-white p-6 lg:block dark:border-gray-800 dark:bg-gray-900\">\n <Link to=\"/\" className=\"text-xl font-bold text-primary-600\">${config.projectName}</Link>\n <nav className=\"mt-8 space-y-1\">\n <Link to=\"/dashboard\" className=\"block rounded-lg px-3 py-2 text-sm font-medium bg-primary-50 text-primary-700 dark:bg-primary-900/20 dark:text-primary-400\">Dashboard</Link>\n </nav>\n </aside>\n <main className=\"flex-1 p-8\">\n <h1 className=\"text-2xl font-bold text-gray-900 dark:text-white\">Dashboard</h1>\n <p className=\"mt-1 text-gray-500\">Visao geral do seu projeto.</p>\n <div className=\"mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-4\">\n {[{ n: 'Usuarios', v: '0' }, { n: 'Receita', v: 'R$ 0' }, { n: 'Pedidos', v: '0' }, { n: 'Conversao', v: '0%' }].map(s => (\n <div key={s.n} className=\"card\"><p className=\"text-sm text-gray-500\">{s.n}</p><p className=\"mt-1 text-3xl font-bold text-gray-900 dark:text-white\">{s.v}</p></div>\n ))}\n </div>\n </main>\n </div>\n );\n}\n`);\n\n // Add react-router-dom dependency\n const pkg = await readPackageJson(webDir);\n if (!pkg.dependencies) pkg.dependencies = {};\n pkg.dependencies['react-router-dom'] = '^7.0.0';\n await writePackageJson(webDir, sortDeps(pkg));\n}\n\nasync function generateVueSaaSPages(config: ProjectConfig, webDir: string): Promise<void> {\n await writeFile(path.join(webDir, 'src', 'App.vue'), `<template>\n <router-view />\n</template>\n`);\n\n await writeFile(path.join(webDir, 'src', 'main.ts'), `import { createApp } from 'vue';\nimport { createRouter, createWebHistory } from 'vue-router';\nimport App from './App.vue';\nimport './style.css';\n\nimport Home from './pages/Home.vue';\nimport Login from './pages/Login.vue';\nimport Register from './pages/Register.vue';\nimport Dashboard from './pages/Dashboard.vue';\n\nconst router = createRouter({\n history: createWebHistory(),\n routes: [\n { path: '/', component: Home },\n { path: '/login', component: Login },\n { path: '/register', component: Register },\n { path: '/dashboard', component: Dashboard },\n ],\n});\n\ncreateApp(App).use(router).mount('#app');\n`);\n\n await writeFile(path.join(webDir, 'src', 'pages', 'Home.vue'), `<template>\n <div class=\"min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-950 dark:to-gray-900\">\n <nav class=\"border-b border-gray-200 bg-white/80 backdrop-blur-sm dark:border-gray-800 dark:bg-gray-950/80\">\n <div class=\"mx-auto flex max-w-7xl items-center justify-between px-6 py-4\">\n <span class=\"text-xl font-bold text-primary-600\">${config.projectName}</span>\n <div class=\"flex items-center gap-4\">\n <router-link to=\"/login\" class=\"text-sm font-medium text-gray-600 hover:text-gray-900 dark:text-gray-400\">Entrar</router-link>\n <router-link to=\"/register\" class=\"btn-primary\">Comecar gratis</router-link>\n </div>\n </div>\n </nav>\n <main class=\"mx-auto max-w-7xl px-6 py-24 text-center\">\n <h1 class=\"text-5xl font-bold tracking-tight text-gray-900 dark:text-white\">${config.projectDescription}</h1>\n <p class=\"mx-auto mt-6 max-w-2xl text-lg text-gray-600 dark:text-gray-400\">Plataforma completa para gerenciar seu negocio.</p>\n <div class=\"mt-10 flex items-center justify-center gap-4\">\n <router-link to=\"/register\" class=\"btn-primary text-base px-8 py-3\">Comecar agora</router-link>\n <router-link to=\"/login\" class=\"btn-secondary text-base px-8 py-3\">Ja tenho conta</router-link>\n </div>\n </main>\n </div>\n</template>\n`);\n\n await writeFile(path.join(webDir, 'src', 'pages', 'Login.vue'), `<template>\n <div class=\"flex min-h-screen items-center justify-center bg-gray-50 px-4 dark:bg-gray-950\">\n <div class=\"w-full max-w-md\">\n <div class=\"text-center mb-8\">\n <router-link to=\"/\" class=\"text-2xl font-bold text-primary-600\">${config.projectName}</router-link>\n <h1 class=\"mt-4 text-2xl font-bold text-gray-900 dark:text-white\">Entrar</h1>\n </div>\n <form @submit.prevent=\"handleSubmit\" class=\"card space-y-4\">\n <div><label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Email</label><input v-model=\"email\" type=\"email\" class=\"input\" required /></div>\n <div><label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Senha</label><input v-model=\"password\" type=\"password\" class=\"input\" required /></div>\n <button type=\"submit\" class=\"btn-primary w-full\">Entrar</button>\n <p class=\"text-center text-sm text-gray-500\">Nao tem conta? <router-link to=\"/register\" class=\"text-primary-600 font-medium\">Criar conta</router-link></p>\n </form>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from 'vue';\nconst email = ref('');\nconst password = ref('');\nconst handleSubmit = async () => {\n const res = await fetch('http://localhost:3001/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email.value, password: password.value }) });\n const data = await res.json();\n if (data.access_token) { localStorage.setItem('token', data.access_token); window.location.href = '/dashboard'; }\n};\n</script>\n`);\n\n await writeFile(path.join(webDir, 'src', 'pages', 'Register.vue'), `<template>\n <div class=\"flex min-h-screen items-center justify-center bg-gray-50 px-4 dark:bg-gray-950\">\n <div class=\"w-full max-w-md\">\n <div class=\"text-center mb-8\">\n <router-link to=\"/\" class=\"text-2xl font-bold text-primary-600\">${config.projectName}</router-link>\n <h1 class=\"mt-4 text-2xl font-bold text-gray-900 dark:text-white\">Criar conta</h1>\n </div>\n <form @submit.prevent=\"handleSubmit\" class=\"card space-y-4\">\n <div><label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Nome</label><input v-model=\"name\" type=\"text\" class=\"input\" required /></div>\n <div><label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Email</label><input v-model=\"email\" type=\"email\" class=\"input\" required /></div>\n <div><label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">Senha</label><input v-model=\"password\" type=\"password\" class=\"input\" minlength=\"6\" required /></div>\n <button type=\"submit\" class=\"btn-primary w-full\">Criar conta</button>\n <p class=\"text-center text-sm text-gray-500\">Ja tem conta? <router-link to=\"/login\" class=\"text-primary-600 font-medium\">Entrar</router-link></p>\n </form>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from 'vue';\nconst name = ref('');\nconst email = ref('');\nconst password = ref('');\nconst handleSubmit = async () => {\n const res = await fetch('http://localhost:3001/api/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name.value, email: email.value, password: password.value }) });\n const data = await res.json();\n if (data.access_token) { localStorage.setItem('token', data.access_token); window.location.href = '/dashboard'; }\n};\n</script>\n`);\n\n await writeFile(path.join(webDir, 'src', 'pages', 'Dashboard.vue'), `<template>\n <div class=\"flex min-h-screen bg-gray-50 dark:bg-gray-950\">\n <aside class=\"hidden w-64 border-r border-gray-200 bg-white p-6 lg:block dark:border-gray-800 dark:bg-gray-900\">\n <router-link to=\"/\" class=\"text-xl font-bold text-primary-600\">${config.projectName}</router-link>\n <nav class=\"mt-8 space-y-1\">\n <router-link to=\"/dashboard\" class=\"block rounded-lg px-3 py-2 text-sm font-medium bg-primary-50 text-primary-700 dark:bg-primary-900/20 dark:text-primary-400\">Dashboard</router-link>\n </nav>\n </aside>\n <main class=\"flex-1 p-8\">\n <h1 class=\"text-2xl font-bold text-gray-900 dark:text-white\">Dashboard</h1>\n <p class=\"mt-1 text-gray-500\">Visao geral do seu projeto.</p>\n <div class=\"mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-4\">\n <div v-for=\"s in stats\" :key=\"s.name\" class=\"card\"><p class=\"text-sm text-gray-500\">{{ s.name }}</p><p class=\"mt-1 text-3xl font-bold text-gray-900 dark:text-white\">{{ s.value }}</p></div>\n </div>\n </main>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nconst stats = [\n { name: 'Usuarios', value: '0' },\n { name: 'Receita', value: 'R$ 0' },\n { name: 'Pedidos', value: '0' },\n { name: 'Conversao', value: '0%' },\n];\n</script>\n`);\n}\n\nasync function generateAngularSaaSPages(config: ProjectConfig, webDir: string): Promise<void> {\n await writeFile(path.join(webDir, 'src', 'app', 'app.component.ts'), `import { Component } from '@angular/core';\nimport { RouterOutlet } from '@angular/router';\n\n@Component({\n selector: 'app-root',\n standalone: true,\n imports: [RouterOutlet],\n template: '<router-outlet></router-outlet>',\n})\nexport class AppComponent {}\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'app.routes.ts'), `import { Routes } from '@angular/router';\nimport { HomeComponent } from './pages/home.component';\nimport { LoginComponent } from './pages/login.component';\nimport { DashboardComponent } from './pages/dashboard.component';\n\nexport const routes: Routes = [\n { path: '', component: HomeComponent },\n { path: 'login', component: LoginComponent },\n { path: 'dashboard', component: DashboardComponent },\n];\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'pages', 'home.component.ts'), `import { Component } from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\n@Component({\n selector: 'app-home',\n standalone: true,\n imports: [RouterLink],\n template: \\`\n <div class=\"min-h-screen bg-gradient-to-br from-gray-50 to-gray-100\">\n <nav class=\"border-b bg-white/80 backdrop-blur-sm\"><div class=\"mx-auto flex max-w-7xl items-center justify-between px-6 py-4\">\n <span class=\"text-xl font-bold text-primary-600\">${config.projectName}</span>\n <div class=\"flex items-center gap-4\">\n <a routerLink=\"/login\" class=\"text-sm font-medium text-gray-600 hover:text-gray-900\">Entrar</a>\n <a routerLink=\"/login\" class=\"btn-primary\">Comecar gratis</a>\n </div>\n </div></nav>\n <main class=\"mx-auto max-w-7xl px-6 py-24 text-center\">\n <h1 class=\"text-5xl font-bold text-gray-900\">${config.projectDescription}</h1>\n <p class=\"mt-6 text-lg text-gray-600\">Plataforma completa para gerenciar seu negocio.</p>\n </main>\n </div>\n \\`,\n})\nexport class HomeComponent {}\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'pages', 'login.component.ts'), `import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { RouterLink } from '@angular/router';\n\n@Component({\n selector: 'app-login',\n standalone: true,\n imports: [FormsModule, RouterLink],\n template: \\`\n <div class=\"flex min-h-screen items-center justify-center bg-gray-50 px-4\">\n <div class=\"w-full max-w-md\">\n <div class=\"text-center mb-8\"><a routerLink=\"/\" class=\"text-2xl font-bold text-primary-600\">${config.projectName}</a><h1 class=\"mt-4 text-2xl font-bold text-gray-900\">Entrar</h1></div>\n <form (ngSubmit)=\"onSubmit()\" class=\"card space-y-4\">\n <div><label class=\"block text-sm font-medium text-gray-700 mb-1\">Email</label><input [(ngModel)]=\"email\" name=\"email\" type=\"email\" class=\"input\" required /></div>\n <div><label class=\"block text-sm font-medium text-gray-700 mb-1\">Senha</label><input [(ngModel)]=\"password\" name=\"password\" type=\"password\" class=\"input\" required /></div>\n <button type=\"submit\" class=\"btn-primary w-full\">Entrar</button>\n </form>\n </div>\n </div>\n \\`,\n})\nexport class LoginComponent {\n email = '';\n password = '';\n async onSubmit() {\n const res = await fetch('http://localhost:3001/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: this.email, password: this.password }) });\n const data = await res.json();\n if (data.access_token) { localStorage.setItem('token', data.access_token); window.location.href = '/dashboard'; }\n }\n}\n`);\n\n await writeFile(path.join(webDir, 'src', 'app', 'pages', 'dashboard.component.ts'), `import { Component } from '@angular/core';\nimport { RouterLink } from '@angular/router';\nimport { NgFor } from '@angular/common';\n\n@Component({\n selector: 'app-dashboard',\n standalone: true,\n imports: [RouterLink, NgFor],\n template: \\`\n <div class=\"flex min-h-screen bg-gray-50\">\n <aside class=\"hidden w-64 border-r bg-white p-6 lg:block\">\n <a routerLink=\"/\" class=\"text-xl font-bold text-primary-600\">${config.projectName}</a>\n <nav class=\"mt-8\"><a routerLink=\"/dashboard\" class=\"block rounded-lg px-3 py-2 text-sm font-medium bg-primary-50 text-primary-700\">Dashboard</a></nav>\n </aside>\n <main class=\"flex-1 p-8\">\n <h1 class=\"text-2xl font-bold text-gray-900\">Dashboard</h1>\n <div class=\"mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-4\">\n <div *ngFor=\"let s of stats\" class=\"card\"><p class=\"text-sm text-gray-500\">{{s.name}}</p><p class=\"mt-1 text-3xl font-bold text-gray-900\">{{s.value}}</p></div>\n </div>\n </main>\n </div>\n \\`,\n})\nexport class DashboardComponent {\n stats = [{ name: 'Usuarios', value: '0' }, { name: 'Receita', value: 'R$ 0' }, { name: 'Pedidos', value: '0' }, { name: 'Conversao', value: '0%' }];\n}\n`);\n\n // Angular needs main.ts with routing\n await writeFile(path.join(webDir, 'src', 'main.ts'), `import { bootstrapApplication } from '@angular/platform-browser';\nimport { provideRouter } from '@angular/router';\nimport { AppComponent } from './app/app.component';\nimport { routes } from './app/app.routes';\n\nbootstrapApplication(AppComponent, {\n providers: [provideRouter(routes)],\n}).catch((err) => console.error(err));\n`);\n}\n","import { readFile, writeFile } from './filesystem.js';\nimport path from 'path';\n\nexport interface PackageJson {\n name: string;\n version: string;\n private?: boolean;\n description?: string;\n type?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n workspaces?: string[];\n [key: string]: unknown;\n}\n\nexport async function readPackageJson(dir: string): Promise<PackageJson> {\n const content = await readFile(path.join(dir, 'package.json'));\n return JSON.parse(content);\n}\n\nexport async function writePackageJson(dir: string, pkg: PackageJson): Promise<void> {\n await writeFile(path.join(dir, 'package.json'), JSON.stringify(pkg, null, 2) + '\\n');\n}\n\nexport function addDependency(\n pkg: PackageJson,\n name: string,\n version: string\n): void {\n if (!pkg.dependencies) pkg.dependencies = {};\n pkg.dependencies[name] = version;\n}\n\nexport function addDevDependency(\n pkg: PackageJson,\n name: string,\n version: string\n): void {\n if (!pkg.devDependencies) pkg.devDependencies = {};\n pkg.devDependencies[name] = version;\n}\n\nexport function addScript(\n pkg: PackageJson,\n name: string,\n command: string\n): void {\n if (!pkg.scripts) pkg.scripts = {};\n pkg.scripts[name] = command;\n}\n\nexport function sortDeps(pkg: PackageJson): PackageJson {\n if (pkg.dependencies) {\n pkg.dependencies = Object.fromEntries(\n Object.entries(pkg.dependencies).sort(([a], [b]) => a.localeCompare(b))\n );\n }\n if (pkg.devDependencies) {\n pkg.devDependencies = Object.fromEntries(\n Object.entries(pkg.devDependencies).sort(([a], [b]) => a.localeCompare(b))\n );\n }\n return pkg;\n}\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const prismaInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, devDependencies, scripts } = opts;\n const provider = config.database === 'postgresql' ? 'postgresql' : 'mysql';\n const dbName = config.projectName.replace(/-/g, '_');\n\n await ensureDir(path.join(apiDir, 'prisma'));\n await ensureDir(path.join(apiDir, 'src', 'database'));\n\n // Schema\n let schema = `generator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"${provider}\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel User {\n id String @id @default(cuid())\n email String @unique\n name String?\n password String?\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n`;\n\n if (config.multiTenant) {\n schema += ` tenantId String @map(\"tenant_id\")\n tenant Tenant @relation(fields: [tenantId], references: [id])\n`;\n }\n\n schema += `\n @@map(\"users\")\n}\n`;\n\n if (config.multiTenant) {\n schema += `\nmodel Tenant {\n id String @id @default(cuid())\n name String\n slug String @unique\n users User[]\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n @@map(\"tenants\")\n}\n`;\n }\n\n await writeFile(path.join(apiDir, 'prisma', 'schema.prisma'), schema);\n\n // Prisma service\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'database', 'prisma.service.ts'), `import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';\nimport { PrismaClient } from '@prisma/client';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {\n async onModuleInit() {\n await this.$connect();\n }\n\n async onModuleDestroy() {\n await this.$disconnect();\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'database', 'prisma.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { PrismaService } from './prisma.service';\n\n@Global()\n@Module({\n providers: [PrismaService],\n exports: [PrismaService],\n})\nexport class PrismaModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'database', 'prisma.ts'), `import { PrismaClient } from '@prisma/client';\n\nconst globalForPrisma = globalThis as unknown as { prisma: PrismaClient };\n\nexport const prisma = globalForPrisma.prisma || new PrismaClient();\n\nif (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;\n\nexport default prisma;\n`);\n }\n\n // Dependencies\n dependencies['@prisma/client'] = deps['@prisma/client'];\n devDependencies['prisma'] = deps.prisma;\n\n // Scripts\n scripts['db:push'] = 'prisma db push';\n scripts['db:migrate'] = 'prisma migrate dev';\n scripts['db:studio'] = 'prisma studio';\n scripts['db:seed'] = 'prisma db seed';\n scripts['db:generate'] = 'prisma generate';\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const mongooseInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'database'));\n await ensureDir(path.join(apiDir, 'src', 'database', 'models'));\n\n // Connection\n if (config.multiTenant) {\n await writeFile(path.join(apiDir, 'src', 'database', 'connection.ts'), `import mongoose from 'mongoose';\n\nconst connections = new Map<string, mongoose.Connection>();\n\nexport async function connectDB(): Promise<mongoose.Connection> {\n const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/${config.projectName.replace(/-/g, '_')}';\n const conn = await mongoose.connect(uri);\n console.log('MongoDB conectado');\n return conn.connection;\n}\n\nexport function getTenantConnection(tenantId: string): mongoose.Connection {\n if (connections.has(tenantId)) {\n return connections.get(tenantId)!;\n }\n\n const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017';\n const conn = mongoose.createConnection(\\`\\${uri}/tenant_\\${tenantId}\\`);\n connections.set(tenantId, conn);\n return conn;\n}\n\nexport default { connectDB, getTenantConnection };\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'database', 'connection.ts'), `import mongoose from 'mongoose';\n\nexport async function connectDB(): Promise<void> {\n const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/${config.projectName.replace(/-/g, '_')}';\n await mongoose.connect(uri);\n console.log('MongoDB conectado');\n}\n\nexport default { connectDB };\n`);\n }\n\n // User model\n await writeFile(path.join(apiDir, 'src', 'database', 'models', 'user.model.ts'), `import mongoose, { Schema, Document } from 'mongoose';\n\nexport interface IUser extends Document {\n email: string;\n name?: string;\n password?: string;\n${config.multiTenant ? ' tenantId: string;\\n' : ''} createdAt: Date;\n updatedAt: Date;\n}\n\nconst UserSchema = new Schema<IUser>(\n {\n email: { type: String, required: true, unique: true },\n name: { type: String },\n password: { type: String },\n${config.multiTenant ? \" tenantId: { type: String, required: true, index: true },\\n\" : ''} },\n { timestamps: true }\n);\n\nexport const User = mongoose.model<IUser>('User', UserSchema);\n`);\n\n dependencies['mongoose'] = deps.mongoose;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const jwtInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'auth'));\n\n envEntries.push(\n { key: 'JWT_SECRET', value: 'change-me-in-production-use-a-strong-secret', category: 'Authentication' },\n { key: 'JWT_EXPIRES_IN', value: '7d', category: 'Authentication' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'jwt.strategy.ts'), `import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n constructor(configService: ConfigService) {\n super({\n jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n ignoreExpiration: false,\n secretOrKey: configService.get<string>('JWT_SECRET'),\n });\n }\n\n async validate(payload: { sub: string; email: string }) {\n return { id: payload.sub, email: payload.email };\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.module.ts'), `import { Module } from '@nestjs/common';\nimport { JwtModule } from '@nestjs/jwt';\nimport { PassportModule } from '@nestjs/passport';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { JwtStrategy } from './jwt.strategy';\n\n@Module({\n imports: [\n PassportModule,\n JwtModule.registerAsync({\n imports: [ConfigModule],\n useFactory: (configService: ConfigService) => ({\n secret: configService.get<string>('JWT_SECRET'),\n signOptions: { expiresIn: configService.get<string>('JWT_EXPIRES_IN', '7d') },\n }),\n inject: [ConfigService],\n }),\n ],\n controllers: [AuthController],\n providers: [AuthService, JwtStrategy],\n exports: [AuthService],\n})\nexport class AuthModule {}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.service.ts'), `import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { JwtService } from '@nestjs/jwt';\nimport * as bcrypt from 'bcryptjs';\n\n@Injectable()\nexport class AuthService {\n constructor(private jwtService: JwtService) {}\n\n async hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, 10);\n }\n\n async comparePassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash);\n }\n\n async generateToken(payload: { sub: string; email: string }): Promise<string> {\n return this.jwtService.sign(payload);\n }\n\n async validateToken(token: string) {\n try {\n return this.jwtService.verify(token);\n } catch {\n throw new UnauthorizedException('Token inválido');\n }\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.controller.ts'), `import { Controller, Post, Body } from '@nestjs/common';\nimport { AuthService } from './auth.service';\n\n@Controller('auth')\nexport class AuthController {\n constructor(private readonly authService: AuthService) {}\n\n @Post('login')\n async login(@Body() body: { email: string; password: string }) {\n // TODO: Buscar usuario no banco e validar password\n const token = await this.authService.generateToken({\n sub: 'user-id',\n email: body.email,\n });\n return { access_token: token };\n }\n\n @Post('register')\n async register(@Body() body: { email: string; password: string; name?: string }) {\n const hashedPassword = await this.authService.hashPassword(body.password);\n // TODO: Criar usuario no banco com hashedPassword\n const token = await this.authService.generateToken({\n sub: 'new-user-id',\n email: body.email,\n });\n return { access_token: token };\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'jwt-auth.guard.ts'), `import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n`);\n\n dependencies['@nestjs/jwt'] = deps['@nestjs/jwt'];\n dependencies['@nestjs/passport'] = deps['@nestjs/passport'];\n dependencies['passport'] = deps.passport;\n dependencies['passport-jwt'] = deps['passport-jwt'];\n devDependencies['@types/passport-jwt'] = deps['@types/passport-jwt'];\n } else {\n // Express / Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'jwt.ts'), `import jwt from 'jsonwebtoken';\n\nconst JWT_SECRET = process.env.JWT_SECRET || 'change-me';\nconst JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '7d';\n\nexport function generateToken(payload: { sub: string; email: string }): string {\n return jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });\n}\n\nexport function verifyToken(token: string) {\n return jwt.verify(token, JWT_SECRET);\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'hash.ts'), `import bcrypt from 'bcryptjs';\n\nexport async function hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, 10);\n}\n\nexport async function comparePassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash);\n}\n`);\n\n if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.middleware.ts'), `import type { Request, Response, NextFunction } from 'express';\nimport { verifyToken } from './jwt.js';\n\nexport function authMiddleware(req: Request, res: Response, next: NextFunction) {\n const authHeader = req.headers.authorization;\n if (!authHeader?.startsWith('Bearer ')) {\n return res.status(401).json({ error: 'Token não fornecido' });\n }\n\n try {\n const token = authHeader.split(' ')[1];\n const payload = verifyToken(token);\n (req as any).user = payload;\n next();\n } catch {\n return res.status(401).json({ error: 'Token inválido' });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.routes.ts'), `import { Router } from 'express';\nimport { generateToken } from './jwt.js';\nimport { hashPassword, comparePassword } from './hash.js';\n\nconst authRouter = Router();\n\nauthRouter.post('/login', async (req, res) => {\n const { email, password } = req.body;\n // TODO: Buscar usuario no banco e validar password\n const token = generateToken({ sub: 'user-id', email });\n res.json({ access_token: token });\n});\n\nauthRouter.post('/register', async (req, res) => {\n const { email, password, name } = req.body;\n const hashedPassword = await hashPassword(password);\n // TODO: Criar usuario no banco com hashedPassword\n const token = generateToken({ sub: 'new-user-id', email });\n res.json({ access_token: token });\n});\n\nexport { authRouter };\n`);\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.hook.ts'), `import type { FastifyRequest, FastifyReply } from 'fastify';\nimport { verifyToken } from './jwt.js';\n\nexport async function authHook(request: FastifyRequest, reply: FastifyReply) {\n const authHeader = request.headers.authorization;\n if (!authHeader?.startsWith('Bearer ')) {\n return reply.status(401).send({ error: 'Token não fornecido' });\n }\n\n try {\n const token = authHeader.split(' ')[1];\n const payload = verifyToken(token);\n (request as any).user = payload;\n } catch {\n return reply.status(401).send({ error: 'Token inválido' });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.routes.ts'), `import type { FastifyInstance } from 'fastify';\nimport { generateToken } from './jwt.js';\nimport { hashPassword } from './hash.js';\n\nexport async function authRoutes(app: FastifyInstance) {\n app.post('/api/auth/login', async (request) => {\n const { email, password } = request.body as { email: string; password: string };\n // TODO: Buscar usuario no banco e validar password\n const token = generateToken({ sub: 'user-id', email });\n return { access_token: token };\n });\n\n app.post('/api/auth/register', async (request) => {\n const { email, password, name } = request.body as { email: string; password: string; name?: string };\n const hashedPassword = await hashPassword(password);\n // TODO: Criar usuario no banco com hashedPassword\n const token = generateToken({ sub: 'new-user-id', email });\n return { access_token: token };\n });\n}\n`);\n }\n\n dependencies['jsonwebtoken'] = deps.jsonwebtoken;\n devDependencies['@types/jsonwebtoken'] = deps['@types/jsonwebtoken'];\n }\n\n dependencies['bcryptjs'] = deps.bcryptjs;\n devDependencies['@types/bcryptjs'] = deps['@types/bcryptjs'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const magicLinkInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'auth'));\n\n envEntries.push(\n { key: 'MAGIC_LINK_EXPIRY_MINUTES', value: '15', category: 'Authentication' },\n { key: 'APP_URL', value: 'http://localhost:3000', category: 'Authentication', comment: 'URL do frontend para o magic link' },\n );\n\n const serviceContent = `import { nanoid } from 'nanoid';\n\ninterface MagicLinkToken {\n token: string;\n email: string;\n expiresAt: Date;\n}\n\n// Em producao, armazene no banco de dados ou Redis\nconst tokens = new Map<string, MagicLinkToken>();\n\nconst EXPIRY_MINUTES = Number(process.env.MAGIC_LINK_EXPIRY_MINUTES) || 15;\nconst APP_URL = process.env.APP_URL || 'http://localhost:3000';\n\nexport function generateMagicLink(email: string): { token: string; url: string } {\n const token = nanoid(32);\n const expiresAt = new Date(Date.now() + EXPIRY_MINUTES * 60 * 1000);\n\n tokens.set(token, { token, email, expiresAt });\n\n const url = \\`\\${APP_URL}/auth/verify?token=\\${token}\\`;\n return { token, url };\n}\n\nexport function verifyMagicLinkToken(token: string): { valid: boolean; email?: string } {\n const entry = tokens.get(token);\n if (!entry) return { valid: false };\n if (entry.expiresAt < new Date()) {\n tokens.delete(token);\n return { valid: false };\n }\n tokens.delete(token);\n return { valid: true, email: entry.email };\n}\n`;\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'magic-link.service.ts'), serviceContent);\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'magic-link.controller.ts'), `import { Controller, Post, Body, Get, Query, BadRequestException } from '@nestjs/common';\nimport { generateMagicLink, verifyMagicLinkToken } from './magic-link.service';\n\n@Controller('auth/magic-link')\nexport class MagicLinkController {\n @Post('send')\n async sendMagicLink(@Body() body: { email: string }) {\n const { url } = generateMagicLink(body.email);\n // TODO: Enviar email com o magic link usando o email service\n console.log('Magic link:', url);\n return { message: 'Magic link enviado para o email' };\n }\n\n @Get('verify')\n async verify(@Query('token') token: string) {\n const result = verifyMagicLinkToken(token);\n if (!result.valid) {\n throw new BadRequestException('Token inválido ou expirado');\n }\n // TODO: Criar sessao/JWT para o usuario\n return { message: 'Login realizado', email: result.email };\n }\n}\n`);\n } else if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'magic-link.routes.ts'), `import { Router } from 'express';\nimport { generateMagicLink, verifyMagicLinkToken } from './magic-link.service.js';\n\nconst magicLinkRouter = Router();\n\nmagicLinkRouter.post('/send', async (req, res) => {\n const { email } = req.body;\n const { url } = generateMagicLink(email);\n // TODO: Enviar email com o magic link usando o email service\n console.log('Magic link:', url);\n res.json({ message: 'Magic link enviado para o email' });\n});\n\nmagicLinkRouter.get('/verify', async (req, res) => {\n const token = req.query.token as string;\n const result = verifyMagicLinkToken(token);\n if (!result.valid) {\n return res.status(400).json({ error: 'Token inválido ou expirado' });\n }\n // TODO: Criar sessao/JWT para o usuario\n res.json({ message: 'Login realizado', email: result.email });\n});\n\nexport { magicLinkRouter };\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'auth', 'magic-link.routes.ts'), `import type { FastifyInstance } from 'fastify';\nimport { generateMagicLink, verifyMagicLinkToken } from './magic-link.service.js';\n\nexport async function magicLinkRoutes(app: FastifyInstance) {\n app.post('/api/auth/magic-link/send', async (request) => {\n const { email } = request.body as { email: string };\n const { url } = generateMagicLink(email);\n // TODO: Enviar email com o magic link usando o email service\n console.log('Magic link:', url);\n return { message: 'Magic link enviado para o email' };\n });\n\n app.get('/api/auth/magic-link/verify', async (request, reply) => {\n const { token } = request.query as { token: string };\n const result = verifyMagicLinkToken(token);\n if (!result.valid) {\n return reply.status(400).send({ error: 'Token inválido ou expirado' });\n }\n // TODO: Criar sessao/JWT para o usuario\n return { message: 'Login realizado', email: result.email };\n });\n}\n`);\n }\n\n dependencies['nanoid'] = deps.nanoid;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const googleOauthInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'auth'));\n\n envEntries.push(\n { key: 'GOOGLE_CLIENT_ID', value: '', category: 'Google OAuth', comment: 'Obtenha em https://console.cloud.google.com' },\n { key: 'GOOGLE_CLIENT_SECRET', value: '', category: 'Google OAuth' },\n { key: 'GOOGLE_CALLBACK_URL', value: 'http://localhost:3001/api/auth/google/callback', category: 'Google OAuth' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'google.strategy.ts'), `import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy, VerifyCallback, Profile } from 'passport-google-oauth20';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class GoogleStrategy extends PassportStrategy(Strategy, 'google') {\n constructor(configService: ConfigService) {\n super({\n clientID: configService.get<string>('GOOGLE_CLIENT_ID'),\n clientSecret: configService.get<string>('GOOGLE_CLIENT_SECRET'),\n callbackURL: configService.get<string>('GOOGLE_CALLBACK_URL'),\n scope: ['email', 'profile'],\n });\n }\n\n async validate(\n accessToken: string,\n refreshToken: string,\n profile: Profile,\n done: VerifyCallback,\n ) {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n googleId: profile.id,\n avatar: profile.photos?.[0]?.value,\n };\n done(null, user);\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'google.controller.ts'), `import { Controller, Get, Req, Res, UseGuards } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport type { Request, Response } from 'express';\n\n@Controller('auth/google')\nexport class GoogleController {\n @Get()\n @UseGuards(AuthGuard('google'))\n async googleAuth() {\n // Redireciona para o Google\n }\n\n @Get('callback')\n @UseGuards(AuthGuard('google'))\n async googleCallback(@Req() req: Request, @Res() res: Response) {\n const user = req.user;\n // TODO: Criar/buscar usuario no banco, gerar JWT\n console.log('Google user:', user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n}\n`);\n\n dependencies['@nestjs/passport'] = deps['@nestjs/passport'];\n dependencies['passport'] = deps.passport;\n } else if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'google.routes.ts'), `import { Router } from 'express';\nimport passport from 'passport';\nimport { Strategy as GoogleStrategy } from 'passport-google-oauth20';\n\npassport.use(\n new GoogleStrategy(\n {\n clientID: process.env.GOOGLE_CLIENT_ID || '',\n clientSecret: process.env.GOOGLE_CLIENT_SECRET || '',\n callbackURL: process.env.GOOGLE_CALLBACK_URL || 'http://localhost:3001/api/auth/google/callback',\n },\n async (accessToken, refreshToken, profile, done) => {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n googleId: profile.id,\n avatar: profile.photos?.[0]?.value,\n };\n // TODO: Criar/buscar usuario no banco\n done(null, user);\n }\n )\n);\n\nconst googleRouter = Router();\n\ngoogleRouter.get('/', passport.authenticate('google', { scope: ['profile', 'email'] }));\n\ngoogleRouter.get(\n '/callback',\n passport.authenticate('google', { session: false }),\n (req, res) => {\n // TODO: Gerar JWT e redirecionar\n console.log('Google user:', req.user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n);\n\nexport { googleRouter };\n`);\n\n dependencies['passport'] = deps.passport;\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'google.routes.ts'), `import type { FastifyInstance } from 'fastify';\n\n// Para Fastify, recomendamos usar @fastify/oauth2\n// npm install @fastify/oauth2\nexport async function googleAuthRoutes(app: FastifyInstance) {\n // TODO: Configurar @fastify/oauth2 para Google\n // Documentacao: https://github.com/fastify/fastify-oauth2\n\n app.get('/api/auth/google', async (request, reply) => {\n const clientId = process.env.GOOGLE_CLIENT_ID;\n const redirectUri = process.env.GOOGLE_CALLBACK_URL;\n const url = \\`https://accounts.google.com/o/oauth2/v2/auth?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&response_type=code&scope=email profile\\`;\n reply.redirect(url);\n });\n\n app.get('/api/auth/google/callback', async (request) => {\n const { code } = request.query as { code: string };\n // TODO: Trocar code por tokens, buscar perfil, criar/buscar usuario\n return { message: 'Google OAuth callback', code };\n });\n}\n`);\n }\n\n dependencies['passport-google-oauth20'] = deps['passport-google-oauth20'];\n devDependencies['@types/passport-google-oauth20'] = deps['@types/passport-google-oauth20'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const bullmqInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'queue'));\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'queue', 'queue.module.ts'), `import { Module } from '@nestjs/common';\nimport { BullModule } from '@nestjs/bullmq';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { ExampleProcessor } from './example.processor';\n\n@Module({\n imports: [\n BullModule.forRootAsync({\n imports: [ConfigModule],\n useFactory: (configService: ConfigService) => ({\n connection: {\n host: configService.get('REDIS_HOST', 'localhost'),\n port: configService.get('REDIS_PORT', 6379),\n password: configService.get('REDIS_PASSWORD') || undefined,\n },\n }),\n inject: [ConfigService],\n }),\n BullModule.registerQueue({ name: 'example' }),\n ],\n providers: [ExampleProcessor],\n exports: [BullModule],\n})\nexport class QueueModule {}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'queue', 'example.processor.ts'), `import { Processor, WorkerHost } from '@nestjs/bullmq';\nimport { Job } from 'bullmq';\n\n@Processor('example')\nexport class ExampleProcessor extends WorkerHost {\n async process(job: Job<{ message: string }>) {\n console.log(\\`Processando job \\${job.id}: \\${job.data.message}\\`);\n // TODO: Implemente a logica do job aqui\n return { success: true };\n }\n}\n`);\n\n dependencies['@nestjs/bullmq'] = deps['@nestjs/bullmq'];\n } else {\n await writeFile(path.join(apiDir, 'src', 'queue', 'queue.config.ts'), `import { Queue, Worker } from 'bullmq';\n\nconst connection = {\n host: process.env.REDIS_HOST || 'localhost',\n port: Number(process.env.REDIS_PORT) || 6379,\n password: process.env.REDIS_PASSWORD || undefined,\n};\n\nexport function createQueue(name: string) {\n return new Queue(name, { connection });\n}\n\nexport function createWorker(\n name: string,\n processor: (job: any) => Promise<any>\n) {\n const worker = new Worker(name, processor, { connection });\n\n worker.on('completed', (job) => {\n console.log(\\`Job \\${job.id} concluido\\`);\n });\n\n worker.on('failed', (job, err) => {\n console.error(\\`Job \\${job?.id} falhou:\\`, err);\n });\n\n return worker;\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'queue', 'example.worker.ts'), `import { createQueue, createWorker } from './queue.config.js';\n\n// Criar fila\nexport const exampleQueue = createQueue('example');\n\n// Criar worker\nexport const exampleWorker = createWorker('example', async (job) => {\n console.log(\\`Processando job \\${job.id}: \\${job.data.message}\\`);\n // TODO: Implemente a logica do job aqui\n return { success: true };\n});\n\n// Funcao helper para adicionar job na fila\nexport async function addExampleJob(data: { message: string }) {\n return exampleQueue.add('process', data);\n}\n`);\n }\n\n dependencies['bullmq'] = deps.bullmq;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const rabbitmqInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'queue'));\n\n envEntries.push(\n { key: 'RABBITMQ_URL', value: 'amqp://guest:guest@localhost:5672', category: 'RabbitMQ' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'queue', 'rabbitmq.config.ts'), `import { Module } from '@nestjs/common';\nimport { ClientsModule, Transport } from '@nestjs/microservices';\n\n@Module({\n imports: [\n ClientsModule.register([\n {\n name: 'RABBITMQ_SERVICE',\n transport: Transport.RMQ,\n options: {\n urls: [process.env.RABBITMQ_URL || 'amqp://guest:guest@localhost:5672'],\n queue: 'main_queue',\n queueOptions: { durable: true },\n },\n },\n ]),\n ],\n exports: [ClientsModule],\n})\nexport class RabbitMQModule {}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'queue', 'rabbitmq.consumer.ts'), `import { Controller } from '@nestjs/common';\nimport { MessagePattern, Payload } from '@nestjs/microservices';\n\n@Controller()\nexport class RabbitMQConsumer {\n @MessagePattern('example_pattern')\n async handleMessage(@Payload() data: any) {\n console.log('Mensagem recebida:', data);\n // TODO: Processar mensagem\n return { success: true };\n }\n}\n`);\n\n dependencies['@nestjs/microservices'] = deps['@nestjs/common'];\n } else {\n await writeFile(path.join(apiDir, 'src', 'queue', 'rabbitmq.ts'), `import amqplib, { type Channel, type Connection } from 'amqplib';\n\nlet connection: Connection | null = null;\nlet channel: Channel | null = null;\n\nexport async function connectRabbitMQ(): Promise<Channel> {\n const url = process.env.RABBITMQ_URL || 'amqp://guest:guest@localhost:5672';\n connection = await amqplib.connect(url);\n channel = await connection.createChannel();\n console.log('RabbitMQ conectado');\n return channel;\n}\n\nexport async function publishMessage(queue: string, message: unknown): Promise<void> {\n if (!channel) throw new Error('RabbitMQ nao conectado');\n await channel.assertQueue(queue, { durable: true });\n channel.sendToQueue(queue, Buffer.from(JSON.stringify(message)), { persistent: true });\n}\n\nexport async function consumeMessages(\n queue: string,\n handler: (msg: unknown) => Promise<void>\n): Promise<void> {\n if (!channel) throw new Error('RabbitMQ nao conectado');\n await channel.assertQueue(queue, { durable: true });\n channel.consume(queue, async (msg) => {\n if (!msg) return;\n try {\n const data = JSON.parse(msg.content.toString());\n await handler(data);\n channel!.ack(msg);\n } catch (err) {\n console.error('Erro ao processar mensagem:', err);\n channel!.nack(msg, false, true);\n }\n });\n}\n\nexport async function closeRabbitMQ(): Promise<void> {\n await channel?.close();\n await connection?.close();\n}\n`);\n }\n\n dependencies['amqplib'] = deps.amqplib;\n devDependencies['@types/amqplib'] = deps['@types/amqplib'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const redisInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'redis'));\n\n envEntries.push(\n { key: 'REDIS_HOST', value: 'localhost', category: 'Redis' },\n { key: 'REDIS_PORT', value: '6379', category: 'Redis' },\n { key: 'REDIS_PASSWORD', value: '', category: 'Redis' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'redis', 'redis.service.ts'), `import { Injectable, OnModuleDestroy } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Redis from 'ioredis';\n\n@Injectable()\nexport class RedisService implements OnModuleDestroy {\n public readonly client: Redis;\n\n constructor(private configService: ConfigService) {\n this.client = new Redis({\n host: this.configService.get('REDIS_HOST', 'localhost'),\n port: this.configService.get('REDIS_PORT', 6379),\n password: this.configService.get('REDIS_PASSWORD') || undefined,\n });\n }\n\n async get(key: string): Promise<string | null> {\n return this.client.get(key);\n }\n\n async set(key: string, value: string, ttlSeconds?: number): Promise<void> {\n if (ttlSeconds) {\n await this.client.set(key, value, 'EX', ttlSeconds);\n } else {\n await this.client.set(key, value);\n }\n }\n\n async del(key: string): Promise<void> {\n await this.client.del(key);\n }\n\n async onModuleDestroy() {\n await this.client.quit();\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'redis', 'redis.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { RedisService } from './redis.service';\n\n@Global()\n@Module({\n providers: [RedisService],\n exports: [RedisService],\n})\nexport class RedisModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'redis', 'redis.ts'), `import Redis from 'ioredis';\n\nconst redis = new Redis({\n host: process.env.REDIS_HOST || 'localhost',\n port: Number(process.env.REDIS_PORT) || 6379,\n password: process.env.REDIS_PASSWORD || undefined,\n});\n\nredis.on('connect', () => console.log('Redis conectado'));\nredis.on('error', (err) => console.error('Redis erro:', err));\n\nexport default redis;\n`);\n }\n\n dependencies['ioredis'] = deps.ioredis;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const smtpInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'email'));\n await ensureDir(path.join(apiDir, 'src', 'infra', 'email', 'templates'));\n\n envEntries.push(\n { key: 'SMTP_HOST', value: '', category: 'SMTP', comment: 'Ex: smtp.gmail.com' },\n { key: 'SMTP_PORT', value: '587', category: 'SMTP' },\n { key: 'SMTP_USER', value: '', category: 'SMTP' },\n { key: 'SMTP_PASS', value: '', category: 'SMTP' },\n { key: 'SMTP_FROM', value: `noreply@${config.projectName}.com`, category: 'SMTP' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'email.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport * as nodemailer from 'nodemailer';\n\n@Injectable()\nexport class EmailService {\n private transporter: nodemailer.Transporter;\n\n constructor(private configService: ConfigService) {\n this.transporter = nodemailer.createTransport({\n host: this.configService.get('SMTP_HOST'),\n port: this.configService.get('SMTP_PORT', 587),\n secure: false,\n auth: {\n user: this.configService.get('SMTP_USER'),\n pass: this.configService.get('SMTP_PASS'),\n },\n });\n }\n\n async sendEmail(to: string, subject: string, html: string): Promise<void> {\n await this.transporter.sendMail({\n from: this.configService.get('SMTP_FROM'),\n to,\n subject,\n html,\n });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'email.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { EmailService } from './email.service';\n\n@Global()\n@Module({\n providers: [EmailService],\n exports: [EmailService],\n})\nexport class EmailModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'email.service.ts'), `import nodemailer from 'nodemailer';\n\nconst transporter = nodemailer.createTransport({\n host: process.env.SMTP_HOST,\n port: Number(process.env.SMTP_PORT) || 587,\n secure: false,\n auth: {\n user: process.env.SMTP_USER,\n pass: process.env.SMTP_PASS,\n },\n});\n\nexport async function sendEmail(to: string, subject: string, html: string): Promise<void> {\n await transporter.sendMail({\n from: process.env.SMTP_FROM,\n to,\n subject,\n html,\n });\n}\n\nexport default { sendEmail };\n`);\n }\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'templates', 'welcome.html'), `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <style>\n body { font-family: system-ui, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }\n .container { max-width: 600px; margin: 0 auto; background: white; border-radius: 8px; padding: 40px; }\n h1 { color: #333; }\n .btn { display: inline-block; padding: 12px 24px; background: #0070f3; color: white; text-decoration: none; border-radius: 6px; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <h1>Bem-vindo ao ${config.projectName}!</h1>\n <p>Sua conta foi criada com sucesso.</p>\n <a href=\"{{APP_URL}}\" class=\"btn\">Acessar</a>\n </div>\n</body>\n</html>\n`);\n\n dependencies['nodemailer'] = deps.nodemailer;\n devDependencies['@types/nodemailer'] = deps['@types/nodemailer'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const minioInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'storage'));\n\n envEntries.push(\n { key: 'MINIO_ENDPOINT', value: 'localhost', category: 'MinIO Storage' },\n { key: 'MINIO_PORT', value: '9000', category: 'MinIO Storage' },\n { key: 'MINIO_ACCESS_KEY', value: 'minioadmin', category: 'MinIO Storage' },\n { key: 'MINIO_SECRET_KEY', value: 'minioadmin', category: 'MinIO Storage' },\n { key: 'MINIO_BUCKET', value: config.projectName.replace(/-/g, '-'), category: 'MinIO Storage' },\n { key: 'MINIO_USE_SSL', value: 'false', category: 'MinIO Storage' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'storage.service.ts'), `import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport * as Minio from 'minio';\n\n@Injectable()\nexport class StorageService implements OnModuleInit {\n private client: Minio.Client;\n private bucket: string;\n\n constructor(private configService: ConfigService) {\n this.bucket = this.configService.get('MINIO_BUCKET', '${config.projectName}');\n this.client = new Minio.Client({\n endPoint: this.configService.get('MINIO_ENDPOINT', 'localhost'),\n port: this.configService.get('MINIO_PORT', 9000),\n useSSL: this.configService.get('MINIO_USE_SSL') === 'true',\n accessKey: this.configService.get('MINIO_ACCESS_KEY', 'minioadmin'),\n secretKey: this.configService.get('MINIO_SECRET_KEY', 'minioadmin'),\n });\n }\n\n async onModuleInit() {\n const exists = await this.client.bucketExists(this.bucket);\n if (!exists) {\n await this.client.makeBucket(this.bucket);\n console.log(\\`Bucket \"\\${this.bucket}\" criado\\`);\n }\n }\n\n async upload(fileName: string, buffer: Buffer, contentType?: string): Promise<string> {\n await this.client.putObject(this.bucket, fileName, buffer, buffer.length, {\n 'Content-Type': contentType || 'application/octet-stream',\n });\n return fileName;\n }\n\n async getFileUrl(fileName: string, expirySeconds = 3600): Promise<string> {\n return this.client.presignedGetObject(this.bucket, fileName, expirySeconds);\n }\n\n async delete(fileName: string): Promise<void> {\n await this.client.removeObject(this.bucket, fileName);\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'storage.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { StorageService } from './storage.service';\n\n@Global()\n@Module({\n providers: [StorageService],\n exports: [StorageService],\n})\nexport class StorageModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'storage.ts'), `import * as Minio from 'minio';\n\nconst BUCKET = process.env.MINIO_BUCKET || '${config.projectName}';\n\nconst minioClient = new Minio.Client({\n endPoint: process.env.MINIO_ENDPOINT || 'localhost',\n port: Number(process.env.MINIO_PORT) || 9000,\n useSSL: process.env.MINIO_USE_SSL === 'true',\n accessKey: process.env.MINIO_ACCESS_KEY || 'minioadmin',\n secretKey: process.env.MINIO_SECRET_KEY || 'minioadmin',\n});\n\nexport async function initStorage(): Promise<void> {\n const exists = await minioClient.bucketExists(BUCKET);\n if (!exists) {\n await minioClient.makeBucket(BUCKET);\n console.log(\\`Bucket \"\\${BUCKET}\" criado\\`);\n }\n}\n\nexport async function upload(fileName: string, buffer: Buffer, contentType?: string): Promise<string> {\n await minioClient.putObject(BUCKET, fileName, buffer, buffer.length, {\n 'Content-Type': contentType || 'application/octet-stream',\n });\n return fileName;\n}\n\nexport async function getFileUrl(fileName: string, expirySeconds = 3600): Promise<string> {\n return minioClient.presignedGetObject(BUCKET, fileName, expirySeconds);\n}\n\nexport async function deleteFile(fileName: string): Promise<void> {\n await minioClient.removeObject(BUCKET, fileName);\n}\n\nexport default { initStorage, upload, getFileUrl, deleteFile };\n`);\n }\n\n dependencies['minio'] = deps.minio;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const pm2Installer: InstallerFn = async (opts) => {\n const { config, projectDir, devDependencies, scripts } = opts;\n\n const ecosystem = `module.exports = {\n apps: [\n {\n name: '${config.projectName}-api',\n script: '${config.backend === 'nestjs' ? 'dist/main.js' : 'dist/index.js'}',\n cwd: './apps/api',\n instances: 'max',\n exec_mode: 'cluster',\n env: {\n NODE_ENV: 'production',\n PORT: 3001,\n },\n watch: false,\n max_memory_restart: '1G',\n // Zero-downtime reload\n wait_ready: true,\n listen_timeout: 10000,\n kill_timeout: 5000,\n },\n ],\n};\n`;\n\n await writeFile(path.join(projectDir, 'ecosystem.config.cjs'), ecosystem);\n\n devDependencies['pm2'] = deps.pm2;\n scripts['pm2:start'] = 'pm2 start ecosystem.config.cjs';\n scripts['pm2:stop'] = 'pm2 stop ecosystem.config.cjs';\n scripts['pm2:restart'] = 'pm2 reload ecosystem.config.cjs';\n scripts['pm2:logs'] = 'pm2 logs';\n};\n","import path from 'path';\nimport type { InstallerFn } from '../types/installers.js';\nimport { ensureDir, writeFile } from '../helpers/filesystem.js';\n\nexport const multiTenantInstaller: InstallerFn = async (opts) => {\n const { config, apiDir } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'tenant'));\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'tenant', 'tenant.middleware.ts'), `import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\n\n@Injectable()\nexport class TenantMiddleware implements NestMiddleware {\n use(req: Request, _res: Response, next: NextFunction) {\n // Extrair tenant do header, subdomain ou path\n const tenantId = req.headers['x-tenant-id'] as string\n || this.extractFromSubdomain(req)\n || 'default';\n\n (req as any).tenantId = tenantId;\n next();\n }\n\n private extractFromSubdomain(req: Request): string | null {\n const host = req.hostname;\n const parts = host.split('.');\n if (parts.length >= 3) {\n return parts[0]; // subdomain como tenant\n }\n return null;\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'tenant', 'tenant.decorator.ts'), `import { createParamDecorator, ExecutionContext } from '@nestjs/common';\n\nexport const TenantId = createParamDecorator(\n (data: unknown, ctx: ExecutionContext): string => {\n const request = ctx.switchToHttp().getRequest();\n return request.tenantId || 'default';\n },\n);\n`);\n\n await writeFile(path.join(apiDir, 'src', 'tenant', 'tenant.module.ts'), `import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';\nimport { TenantMiddleware } from './tenant.middleware';\n\n@Module({})\nexport class TenantModule implements NestModule {\n configure(consumer: MiddlewareConsumer) {\n consumer.apply(TenantMiddleware).forRoutes('*');\n }\n}\n`);\n } else if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'tenant', 'tenant.middleware.ts'), `import type { Request, Response, NextFunction } from 'express';\n\nexport function tenantMiddleware(req: Request, _res: Response, next: NextFunction) {\n const tenantId = req.headers['x-tenant-id'] as string\n || extractFromSubdomain(req)\n || 'default';\n\n (req as any).tenantId = tenantId;\n next();\n}\n\nfunction extractFromSubdomain(req: Request): string | null {\n const host = req.hostname;\n const parts = host.split('.');\n if (parts.length >= 3) {\n return parts[0];\n }\n return null;\n}\n`);\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'tenant', 'tenant.plugin.ts'), `import type { FastifyInstance, FastifyRequest } from 'fastify';\nimport fp from 'fastify-plugin';\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n tenantId: string;\n }\n}\n\nasync function tenantPlugin(app: FastifyInstance) {\n app.decorateRequest('tenantId', 'default');\n\n app.addHook('onRequest', async (request: FastifyRequest) => {\n const tenantId = (request.headers['x-tenant-id'] as string)\n || extractFromSubdomain(request)\n || 'default';\n\n request.tenantId = tenantId;\n });\n}\n\nfunction extractFromSubdomain(request: FastifyRequest): string | null {\n const host = request.hostname;\n const parts = host.split('.');\n if (parts.length >= 3) {\n return parts[0];\n }\n return null;\n}\n\nexport default fp(tenantPlugin, { name: 'tenant' });\n`);\n }\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const viacepInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'viacep'));\n\n const serviceContent = `import axios from 'axios';\n\nexport interface ViaCepResponse {\n cep: string;\n logradouro: string;\n complemento: string;\n bairro: string;\n localidade: string;\n uf: string;\n ibge: string;\n erro?: boolean;\n}\n\nconst VIACEP_URL = 'https://viacep.com.br/ws';\n\nexport async function fetchAddress(cep: string): Promise<ViaCepResponse | null> {\n const cleanCep = cep.replace(/\\\\D/g, '');\n if (cleanCep.length !== 8) throw new Error('CEP deve ter 8 dígitos');\n\n const { data } = await axios.get<ViaCepResponse>(\\`\\${VIACEP_URL}/\\${cleanCep}/json\\`);\n if (data.erro) return null;\n return data;\n}\n`;\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'viacep', 'viacep.service.ts'), `import { Injectable } from '@nestjs/common';\nimport axios from 'axios';\n\nexport interface ViaCepResponse {\n cep: string;\n logradouro: string;\n complemento: string;\n bairro: string;\n localidade: string;\n uf: string;\n ibge: string;\n erro?: boolean;\n}\n\n@Injectable()\nexport class ViaCepService {\n private readonly baseUrl = 'https://viacep.com.br/ws';\n\n async fetchAddress(cep: string): Promise<ViaCepResponse | null> {\n const cleanCep = cep.replace(/\\\\D/g, '');\n if (cleanCep.length !== 8) throw new Error('CEP deve ter 8 dígitos');\n\n const { data } = await axios.get<ViaCepResponse>(\\`\\${this.baseUrl}/\\${cleanCep}/json\\`);\n if (data.erro) return null;\n return data;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'viacep', 'viacep.service.ts'), serviceContent);\n }\n\n dependencies['axios'] = deps.axios;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const whatsappInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'whatsapp'));\n\n envEntries.push(\n { key: 'WHATSAPP_API_TOKEN', value: '', category: 'WhatsApp', comment: 'Token da API Meta WhatsApp Business' },\n { key: 'WHATSAPP_PHONE_ID', value: '', category: 'WhatsApp' },\n { key: 'WHATSAPP_VERIFY_TOKEN', value: 'my-verify-token', category: 'WhatsApp', comment: 'Token de verificacao do webhook' },\n );\n\n const serviceContent = config.backend === 'nestjs'\n ? `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport axios from 'axios';\n\n@Injectable()\nexport class WhatsAppService {\n private readonly apiUrl: string;\n private readonly token: string;\n\n constructor(private configService: ConfigService) {\n const phoneId = this.configService.get('WHATSAPP_PHONE_ID');\n this.apiUrl = \\`https://graph.facebook.com/v18.0/\\${phoneId}/messages\\`;\n this.token = this.configService.get('WHATSAPP_API_TOKEN', '');\n }\n\n async sendMessage(to: string, message: string): Promise<void> {\n await axios.post(\n this.apiUrl,\n {\n messaging_product: 'whatsapp',\n to,\n type: 'text',\n text: { body: message },\n },\n {\n headers: {\n Authorization: \\`Bearer \\${this.token}\\`,\n 'Content-Type': 'application/json',\n },\n }\n );\n }\n\n async sendTemplate(to: string, templateName: string, language = 'pt_BR'): Promise<void> {\n await axios.post(\n this.apiUrl,\n {\n messaging_product: 'whatsapp',\n to,\n type: 'template',\n template: { name: templateName, language: { code: language } },\n },\n {\n headers: {\n Authorization: \\`Bearer \\${this.token}\\`,\n 'Content-Type': 'application/json',\n },\n }\n );\n }\n}\n`\n : `import axios from 'axios';\n\nconst PHONE_ID = process.env.WHATSAPP_PHONE_ID;\nconst API_URL = \\`https://graph.facebook.com/v18.0/\\${PHONE_ID}/messages\\`;\nconst TOKEN = process.env.WHATSAPP_API_TOKEN || '';\n\nconst headers = {\n Authorization: \\`Bearer \\${TOKEN}\\`,\n 'Content-Type': 'application/json',\n};\n\nexport async function sendMessage(to: string, message: string): Promise<void> {\n await axios.post(API_URL, {\n messaging_product: 'whatsapp',\n to,\n type: 'text',\n text: { body: message },\n }, { headers });\n}\n\nexport async function sendTemplate(to: string, templateName: string, language = 'pt_BR'): Promise<void> {\n await axios.post(API_URL, {\n messaging_product: 'whatsapp',\n to,\n type: 'template',\n template: { name: templateName, language: { code: language } },\n }, { headers });\n}\n`;\n\n await writeFile(path.join(apiDir, 'src', 'integrations', 'whatsapp', 'whatsapp.service.ts'), serviceContent);\n\n dependencies['axios'] = deps.axios;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const stripeInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'stripe'));\n\n envEntries.push(\n { key: 'STRIPE_SECRET_KEY', value: '', category: 'Stripe', comment: 'Obtenha em https://dashboard.stripe.com' },\n { key: 'STRIPE_WEBHOOK_SECRET', value: '', category: 'Stripe' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'stripe', 'stripe.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Stripe from 'stripe';\n\n@Injectable()\nexport class StripeService {\n private stripe: Stripe;\n\n constructor(private configService: ConfigService) {\n this.stripe = new Stripe(this.configService.get('STRIPE_SECRET_KEY', ''), {\n apiVersion: '2024-12-18.acacia',\n });\n }\n\n async createCheckoutSession(params: {\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n }) {\n return this.stripe.checkout.sessions.create({\n mode: 'subscription',\n payment_method_types: ['card'],\n line_items: [{ price: params.priceId, quantity: 1 }],\n success_url: params.successUrl,\n cancel_url: params.cancelUrl,\n customer_email: params.customerEmail,\n });\n }\n\n async createPaymentIntent(amount: number, currency = 'brl') {\n return this.stripe.paymentIntents.create({\n amount,\n currency,\n });\n }\n\n constructWebhookEvent(body: Buffer, signature: string) {\n const webhookSecret = this.configService.get('STRIPE_WEBHOOK_SECRET', '');\n return this.stripe.webhooks.constructEvent(body, signature, webhookSecret);\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'stripe', 'stripe.service.ts'), `import Stripe from 'stripe';\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY || '', {\n apiVersion: '2024-12-18.acacia',\n});\n\nexport async function createCheckoutSession(params: {\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n}) {\n return stripe.checkout.sessions.create({\n mode: 'subscription',\n payment_method_types: ['card'],\n line_items: [{ price: params.priceId, quantity: 1 }],\n success_url: params.successUrl,\n cancel_url: params.cancelUrl,\n customer_email: params.customerEmail,\n });\n}\n\nexport async function createPaymentIntent(amount: number, currency = 'brl') {\n return stripe.paymentIntents.create({ amount, currency });\n}\n\nexport function constructWebhookEvent(body: Buffer, signature: string) {\n return stripe.webhooks.constructEvent(\n body,\n signature,\n process.env.STRIPE_WEBHOOK_SECRET || ''\n );\n}\n`);\n }\n\n dependencies['stripe'] = deps.stripe;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const mercadoPagoInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'mercado-pago'));\n\n envEntries.push(\n { key: 'MERCADOPAGO_ACCESS_TOKEN', value: '', category: 'Mercado Pago', comment: 'Obtenha em https://www.mercadopago.com.br/developers' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'mercado-pago', 'mercado-pago.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { MercadoPagoConfig, Preference, Payment } from 'mercadopago';\n\n@Injectable()\nexport class MercadoPagoService {\n private client: MercadoPagoConfig;\n\n constructor(private configService: ConfigService) {\n this.client = new MercadoPagoConfig({\n accessToken: this.configService.get('MERCADOPAGO_ACCESS_TOKEN', ''),\n });\n }\n\n async createPreference(params: {\n title: string;\n quantity: number;\n unitPrice: number;\n successUrl?: string;\n failureUrl?: string;\n }) {\n const preference = new Preference(this.client);\n return preference.create({\n body: {\n items: [\n {\n id: 'item-1',\n title: params.title,\n quantity: params.quantity,\n unit_price: params.unitPrice,\n currency_id: 'BRL',\n },\n ],\n back_urls: {\n success: params.successUrl || 'http://localhost:3000/success',\n failure: params.failureUrl || 'http://localhost:3000/failure',\n },\n auto_return: 'approved',\n },\n });\n }\n\n async getPayment(paymentId: string) {\n const payment = new Payment(this.client);\n return payment.get({ id: paymentId });\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'mercado-pago', 'mercado-pago.service.ts'), `import { MercadoPagoConfig, Preference, Payment } from 'mercadopago';\n\nconst client = new MercadoPagoConfig({\n accessToken: process.env.MERCADOPAGO_ACCESS_TOKEN || '',\n});\n\nexport async function createPreference(params: {\n title: string;\n quantity: number;\n unitPrice: number;\n successUrl?: string;\n failureUrl?: string;\n}) {\n const preference = new Preference(client);\n return preference.create({\n body: {\n items: [\n {\n id: 'item-1',\n title: params.title,\n quantity: params.quantity,\n unit_price: params.unitPrice,\n currency_id: 'BRL',\n },\n ],\n back_urls: {\n success: params.successUrl || 'http://localhost:3000/success',\n failure: params.failureUrl || 'http://localhost:3000/failure',\n },\n auto_return: 'approved',\n },\n });\n}\n\nexport async function getPayment(paymentId: string) {\n const payment = new Payment(client);\n return payment.get({ id: paymentId });\n}\n`);\n }\n\n dependencies['mercadopago'] = deps.mercadopago;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const abacatePayInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'abacate-pay'));\n\n envEntries.push(\n { key: 'ABACATEPAY_API_KEY', value: '', category: 'AbacatePay', comment: 'Obtenha em https://abacatepay.com' },\n { key: 'ABACATEPAY_API_URL', value: 'https://api.abacatepay.com/v1', category: 'AbacatePay' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'abacate-pay', 'abacate-pay.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport axios, { type AxiosInstance } from 'axios';\n\n@Injectable()\nexport class AbacatePayService {\n private client: AxiosInstance;\n\n constructor(private configService: ConfigService) {\n this.client = axios.create({\n baseURL: this.configService.get('ABACATEPAY_API_URL', 'https://api.abacatepay.com/v1'),\n headers: {\n Authorization: \\`Bearer \\${this.configService.get('ABACATEPAY_API_KEY')}\\`,\n 'Content-Type': 'application/json',\n },\n });\n }\n\n async createPayment(params: {\n amount: number;\n description: string;\n customerEmail: string;\n }) {\n const { data } = await this.client.post('/payments', {\n amount: params.amount,\n description: params.description,\n customer: { email: params.customerEmail },\n });\n return data;\n }\n\n async getPayment(paymentId: string) {\n const { data } = await this.client.get(\\`/payments/\\${paymentId}\\`);\n return data;\n }\n\n async createPixPayment(params: {\n amount: number;\n description: string;\n customerEmail: string;\n }) {\n const { data } = await this.client.post('/payments/pix', {\n amount: params.amount,\n description: params.description,\n customer: { email: params.customerEmail },\n });\n return data;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'abacate-pay', 'abacate-pay.service.ts'), `import axios from 'axios';\n\nconst API_URL = process.env.ABACATEPAY_API_URL || 'https://api.abacatepay.com/v1';\nconst API_KEY = process.env.ABACATEPAY_API_KEY || '';\n\nconst client = axios.create({\n baseURL: API_URL,\n headers: {\n Authorization: \\`Bearer \\${API_KEY}\\`,\n 'Content-Type': 'application/json',\n },\n});\n\nexport async function createPayment(params: {\n amount: number;\n description: string;\n customerEmail: string;\n}) {\n const { data } = await client.post('/payments', {\n amount: params.amount,\n description: params.description,\n customer: { email: params.customerEmail },\n });\n return data;\n}\n\nexport async function getPayment(paymentId: string) {\n const { data } = await client.get(\\`/payments/\\${paymentId}\\`);\n return data;\n}\n\nexport async function createPixPayment(params: {\n amount: number;\n description: string;\n customerEmail: string;\n}) {\n const { data } = await client.post('/payments/pix', {\n amount: params.amount,\n description: params.description,\n customer: { email: params.customerEmail },\n });\n return data;\n}\n`);\n }\n\n dependencies['axios'] = deps.axios;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const zodInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n const validationDir = path.join(apiDir, 'src', 'common', 'validation');\n const schemasDir = path.join(validationDir, 'schemas');\n\n await ensureDir(validationDir);\n await ensureDir(schemasDir);\n\n // ── Shared example schemas ──────────────────────────────────────────────\n await writeFile(path.join(schemasDir, 'example.schema.ts'), `import { z } from 'zod';\n\n// ── User ──────────────────────────────────────────────────────────────────\n\nexport const CreateUserSchema = z.object({\n name: z\n .string()\n .min(2, 'Nome deve ter pelo menos 2 caracteres')\n .max(100, 'Nome deve ter no maximo 100 caracteres'),\n email: z\n .string()\n .email('Email invalido'),\n password: z\n .string()\n .min(8, 'Senha deve ter pelo menos 8 caracteres')\n .max(128, 'Senha deve ter no maximo 128 caracteres')\n .regex(\n /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\\\d)/,\n 'Senha deve conter pelo menos uma letra minuscula, uma maiuscula e um numero',\n ),\n});\n\nexport type CreateUserDto = z.infer<typeof CreateUserSchema>;\n\n// ── Login ─────────────────────────────────────────────────────────────────\n\nexport const LoginSchema = z.object({\n email: z\n .string()\n .email('Email invalido'),\n password: z\n .string()\n .min(1, 'Senha e obrigatoria'),\n});\n\nexport type LoginDto = z.infer<typeof LoginSchema>;\n\n// ── Update Profile ────────────────────────────────────────────────────────\n\nexport const UpdateProfileSchema = z.object({\n name: z\n .string()\n .min(2, 'Nome deve ter pelo menos 2 caracteres')\n .max(100, 'Nome deve ter no maximo 100 caracteres')\n .optional(),\n avatarUrl: z\n .string()\n .url('URL do avatar invalida')\n .optional(),\n});\n\nexport type UpdateProfileDto = z.infer<typeof UpdateProfileSchema>;\n\n// ── Pagination ────────────────────────────────────────────────────────────\n\nexport const PaginationSchema = z.object({\n page: z.coerce.number().int().min(1).default(1),\n limit: z.coerce.number().int().min(1).max(100).default(20),\n});\n\nexport type PaginationDto = z.infer<typeof PaginationSchema>;\n\n// ── ID Param ──────────────────────────────────────────────────────────────\n\nexport const IdParamSchema = z.object({\n id: z.string().uuid('ID deve ser um UUID valido'),\n});\n\nexport type IdParamDto = z.infer<typeof IdParamSchema>;\n`);\n\n // ── Framework-specific validation infrastructure ────────────────────────\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(validationDir, 'zod-validation.pipe.ts'), `import { BadRequestException, type PipeTransform, Injectable } from '@nestjs/common';\nimport { ZodSchema, ZodError } from 'zod';\n\n@Injectable()\nexport class ZodValidationPipe implements PipeTransform {\n constructor(private schema: ZodSchema) {}\n\n transform(value: unknown) {\n const result = this.schema.safeParse(value);\n\n if (!result.success) {\n const errors = this.formatErrors(result.error);\n throw new BadRequestException({\n message: 'Erro de validacao',\n errors,\n });\n }\n\n return result.data;\n }\n\n private formatErrors(error: ZodError): Record<string, string[]> {\n const formatted: Record<string, string[]> = {};\n\n for (const issue of error.issues) {\n const path = issue.path.join('.') || '_root';\n if (!formatted[path]) {\n formatted[path] = [];\n }\n formatted[path].push(issue.message);\n }\n\n return formatted;\n }\n}\n\n/**\n * Usage in a NestJS controller:\n *\n * import { ZodValidationPipe } from '../common/validation/zod-validation.pipe';\n * import { CreateUserSchema, CreateUserDto } from '../common/validation/schemas/example.schema';\n *\n * @Post()\n * create(@Body(new ZodValidationPipe(CreateUserSchema)) dto: CreateUserDto) {\n * return this.usersService.create(dto);\n * }\n */\n`);\n\n dependencies['nestjs-zod'] = deps['nestjs-zod'];\n } else {\n // Express / Fastify\n if (config.backend === 'express') {\n await writeFile(path.join(validationDir, 'validate.ts'), `import type { Request, Response, NextFunction } from 'express';\nimport { ZodSchema, ZodError } from 'zod';\n\n/**\n * Express middleware factory that validates req.body against a Zod schema.\n * On success, replaces req.body with the parsed (and coerced) data.\n * On failure, responds with 400 and structured validation errors.\n *\n * Usage:\n * import { validate } from '../common/validation/validate';\n * import { CreateUserSchema } from '../common/validation/schemas/example.schema';\n *\n * router.post('/users', validate(CreateUserSchema), (req, res) => {\n * // req.body is fully typed and validated\n * res.json(req.body);\n * });\n */\nexport function validate(schema: ZodSchema) {\n return (req: Request, res: Response, next: NextFunction) => {\n const result = schema.safeParse(req.body);\n\n if (!result.success) {\n const errors = formatZodErrors(result.error);\n return res.status(400).json({\n message: 'Erro de validacao',\n errors,\n });\n }\n\n req.body = result.data;\n next();\n };\n}\n\n/**\n * Validates query parameters against a Zod schema.\n *\n * Usage:\n * import { validateQuery } from '../common/validation/validate';\n * import { PaginationSchema } from '../common/validation/schemas/example.schema';\n *\n * router.get('/users', validateQuery(PaginationSchema), (req, res) => {\n * const { page, limit } = req.query as any;\n * });\n */\nexport function validateQuery(schema: ZodSchema) {\n return (req: Request, res: Response, next: NextFunction) => {\n const result = schema.safeParse(req.query);\n\n if (!result.success) {\n const errors = formatZodErrors(result.error);\n return res.status(400).json({\n message: 'Erro de validacao',\n errors,\n });\n }\n\n (req as any).validatedQuery = result.data;\n next();\n };\n}\n\n/**\n * Validates route parameters against a Zod schema.\n *\n * Usage:\n * import { validateParams } from '../common/validation/validate';\n * import { IdParamSchema } from '../common/validation/schemas/example.schema';\n *\n * router.get('/users/:id', validateParams(IdParamSchema), (req, res) => {\n * const { id } = req.params;\n * });\n */\nexport function validateParams(schema: ZodSchema) {\n return (req: Request, res: Response, next: NextFunction) => {\n const result = schema.safeParse(req.params);\n\n if (!result.success) {\n const errors = formatZodErrors(result.error);\n return res.status(400).json({\n message: 'Erro de validacao',\n errors,\n });\n }\n\n req.params = result.data;\n next();\n };\n}\n\nfunction formatZodErrors(error: ZodError): Record<string, string[]> {\n const formatted: Record<string, string[]> = {};\n\n for (const issue of error.issues) {\n const path = issue.path.join('.') || '_root';\n if (!formatted[path]) {\n formatted[path] = [];\n }\n formatted[path].push(issue.message);\n }\n\n return formatted;\n}\n`);\n } else {\n // Fastify\n await writeFile(path.join(validationDir, 'validate.ts'), `import type { FastifyRequest, FastifyReply, HookHandlerDoneFunction } from 'fastify';\nimport { ZodSchema, ZodError } from 'zod';\n\n/**\n * Fastify preHandler hook factory that validates request.body against a Zod schema.\n * On success, replaces request.body with the parsed (and coerced) data.\n * On failure, responds with 400 and structured validation errors.\n *\n * Usage:\n * import { validate } from '../common/validation/validate';\n * import { CreateUserSchema } from '../common/validation/schemas/example.schema';\n *\n * app.post('/users', { preHandler: validate(CreateUserSchema) }, async (request) => {\n * // request.body is fully validated\n * return request.body;\n * });\n */\nexport function validate(schema: ZodSchema) {\n return (request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => {\n const result = schema.safeParse(request.body);\n\n if (!result.success) {\n const errors = formatZodErrors(result.error);\n reply.status(400).send({\n message: 'Erro de validacao',\n errors,\n });\n return;\n }\n\n request.body = result.data;\n done();\n };\n}\n\n/**\n * Validates query parameters against a Zod schema.\n *\n * Usage:\n * import { validateQuery } from '../common/validation/validate';\n * import { PaginationSchema } from '../common/validation/schemas/example.schema';\n *\n * app.get('/users', { preHandler: validateQuery(PaginationSchema) }, async (request) => {\n * const query = (request as any).validatedQuery;\n * });\n */\nexport function validateQuery(schema: ZodSchema) {\n return (request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => {\n const result = schema.safeParse(request.query);\n\n if (!result.success) {\n const errors = formatZodErrors(result.error);\n reply.status(400).send({\n message: 'Erro de validacao',\n errors,\n });\n return;\n }\n\n (request as any).validatedQuery = result.data;\n done();\n };\n}\n\n/**\n * Validates route parameters against a Zod schema.\n *\n * Usage:\n * import { validateParams } from '../common/validation/validate';\n * import { IdParamSchema } from '../common/validation/schemas/example.schema';\n *\n * app.get('/users/:id', { preHandler: validateParams(IdParamSchema) }, async (request) => {\n * const { id } = request.params as any;\n * });\n */\nexport function validateParams(schema: ZodSchema) {\n return (request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => {\n const result = schema.safeParse(request.params);\n\n if (!result.success) {\n const errors = formatZodErrors(result.error);\n reply.status(400).send({\n message: 'Erro de validacao',\n errors,\n });\n return;\n }\n\n (request as any).validatedParams = result.data;\n done();\n };\n}\n\nfunction formatZodErrors(error: ZodError): Record<string, string[]> {\n const formatted: Record<string, string[]> = {};\n\n for (const issue of error.issues) {\n const path = issue.path.join('.') || '_root';\n if (!formatted[path]) {\n formatted[path] = [];\n }\n formatted[path].push(issue.message);\n }\n\n return formatted;\n}\n`);\n }\n }\n\n // ── Dependencies ────────────────────────────────────────────────────────\n\n dependencies['zod'] = deps.zod;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const rateLimitingInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n envEntries.push(\n { key: 'RATE_LIMIT_MAX', value: '100', category: 'Rate Limiting' },\n { key: 'RATE_LIMIT_WINDOW_MS', value: '60000', category: 'Rate Limiting' },\n );\n\n if (config.backend === 'nestjs') {\n await ensureDir(path.join(apiDir, 'src', 'common', 'throttle'));\n\n await writeFile(path.join(apiDir, 'src', 'common', 'throttle', 'throttle.module.ts'), `import { Module } from '@nestjs/common';\nimport { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { APP_GUARD } from '@nestjs/core';\n\n/**\n * Global rate-limiting module using @nestjs/throttler.\n *\n * Provides three throttle presets:\n * - short : burst protection (10 req / 10s)\n * - medium : general API limit (RATE_LIMIT_MAX req / RATE_LIMIT_WINDOW_MS)\n * - long : sustained ceiling (200 req / 600s)\n *\n * The ThrottlerGuard is registered globally via APP_GUARD, so every\n * route is protected by default. To skip throttling on a specific\n * handler or controller, use the @SkipThrottle() decorator.\n * To override limits per-route, use @Throttle({ default: { limit, ttl } }).\n */\n@Module({\n imports: [\n ThrottlerModule.forRootAsync({\n imports: [ConfigModule],\n useFactory: (configService: ConfigService) => ({\n throttlers: [\n {\n name: 'short',\n ttl: 10_000,\n limit: 10,\n },\n {\n name: 'medium',\n ttl: configService.get<number>('RATE_LIMIT_WINDOW_MS', 60_000),\n limit: configService.get<number>('RATE_LIMIT_MAX', 100),\n },\n {\n name: 'long',\n ttl: 600_000,\n limit: 200,\n },\n ],\n }),\n inject: [ConfigService],\n }),\n ],\n providers: [\n {\n provide: APP_GUARD,\n useClass: ThrottlerGuard,\n },\n ],\n})\nexport class ThrottleModule {}\n`);\n\n dependencies['@nestjs/throttler'] = deps['@nestjs/throttler'];\n } else if (config.backend === 'express') {\n await ensureDir(path.join(apiDir, 'src', 'middlewares'));\n\n await writeFile(path.join(apiDir, 'src', 'middlewares', 'rateLimiter.ts'), `import rateLimit, { type Options } from 'express-rate-limit';\n\n/**\n * Default rate limiter for general API routes.\n *\n * Uses RATE_LIMIT_MAX and RATE_LIMIT_WINDOW_MS env vars with sensible\n * SaaS defaults (100 requests per 60 seconds).\n *\n * Usage:\n * app.use('/api', defaultLimiter);\n */\nexport const defaultLimiter = rateLimit({\n windowMs: Number(process.env.RATE_LIMIT_WINDOW_MS) || 60_000,\n max: Number(process.env.RATE_LIMIT_MAX) || 100,\n standardHeaders: 'draft-7',\n legacyHeaders: false,\n message: {\n error: 'Too many requests, please try again later.',\n },\n});\n\n/**\n * Strict limiter for sensitive endpoints (login, register, password reset).\n *\n * 10 requests per 15-minute window to mitigate brute-force attacks.\n *\n * Usage:\n * app.use('/api/auth', strictLimiter);\n */\nexport const strictLimiter = rateLimit({\n windowMs: 15 * 60 * 1000,\n max: 10,\n standardHeaders: 'draft-7',\n legacyHeaders: false,\n message: {\n error: 'Too many attempts, please try again later.',\n },\n});\n\n/**\n * Factory to create a custom rate limiter with specific options.\n *\n * Usage:\n * const uploadLimiter = createLimiter({ windowMs: 60_000, max: 5 });\n * app.use('/api/upload', uploadLimiter);\n */\nexport function createLimiter(overrides: Partial<Options> = {}) {\n return rateLimit({\n windowMs: 60_000,\n max: 100,\n standardHeaders: 'draft-7',\n legacyHeaders: false,\n message: {\n error: 'Too many requests, please try again later.',\n },\n ...overrides,\n });\n}\n`);\n\n dependencies['express-rate-limit'] = deps['express-rate-limit'];\n } else {\n // Fastify\n await ensureDir(path.join(apiDir, 'src', 'plugins'));\n\n await writeFile(path.join(apiDir, 'src', 'plugins', 'rateLimiter.ts'), `import type { FastifyInstance } from 'fastify';\nimport fp from 'fastify-plugin';\nimport rateLimit from '@fastify/rate-limit';\n\n/**\n * Rate-limiting plugin for Fastify using @fastify/rate-limit.\n *\n * Registers a global rate limiter with sensible SaaS defaults.\n * Individual routes can override limits via route-level options:\n *\n * app.get('/heavy', { config: { rateLimit: { max: 5, timeWindow: '1 minute' } } }, handler);\n *\n * To disable rate limiting on a specific route:\n *\n * app.get('/health', { config: { rateLimit: false } }, handler);\n */\nasync function rateLimiterPlugin(app: FastifyInstance) {\n await app.register(rateLimit, {\n max: Number(process.env.RATE_LIMIT_MAX) || 100,\n timeWindow: Number(process.env.RATE_LIMIT_WINDOW_MS) || 60_000,\n errorResponseBuilder: (_request, context) => ({\n statusCode: 429,\n error: 'Too Many Requests',\n message: 'Too many requests, please try again later.',\n retryAfter: context.after,\n }),\n });\n}\n\nexport default fp(rateLimiterPlugin, {\n name: 'rate-limiter',\n});\n`);\n\n dependencies['@fastify/rate-limit'] = deps['@fastify/rate-limit'];\n }\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const loggingInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n envEntries.push({\n key: 'LOG_LEVEL',\n value: 'info',\n comment: 'trace | debug | info | warn | error | fatal',\n category: 'Logging',\n });\n\n if (config.backend === 'nestjs') {\n await installNestJSLogger(apiDir, dependencies);\n } else if (config.backend === 'express') {\n await installExpressLogger(apiDir, dependencies);\n } else {\n await installFastifyLogger(apiDir, dependencies);\n }\n};\n\n// ---------------------------------------------------------------------------\n// NestJS – nestjs-pino with LoggerModule + lightweight wrapper service\n// ---------------------------------------------------------------------------\nasync function installNestJSLogger(\n apiDir: string,\n dependencies: Record<string, string>,\n) {\n const loggerDir = path.join(apiDir, 'src', 'common', 'logger');\n await ensureDir(loggerDir);\n\n // ── logger.module.ts ────────────────────────────────────────────────────\n await writeFile(path.join(loggerDir, 'logger.module.ts'), `import { Module } from '@nestjs/common';\nimport { LoggerModule as PinoLoggerModule } from 'nestjs-pino';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { AppLoggerService } from './logger.service';\n\n@Module({\n imports: [\n PinoLoggerModule.forRootAsync({\n imports: [ConfigModule],\n useFactory: (configService: ConfigService) => {\n const isProduction = configService.get('NODE_ENV') === 'production';\n\n return {\n pinoHttp: {\n level: configService.get('LOG_LEVEL', 'info'),\n\n // Generate a unique request ID for correlation across services\n genReqId: (req: any) =>\n req.headers['x-request-id'] ??\n crypto.randomUUID(),\n\n // Redact sensitive headers from log output\n redact: {\n paths: [\n 'req.headers.authorization',\n 'req.headers.cookie',\n ],\n censor: '[REDACTED]',\n },\n\n // Serializers – keep logs lean\n serializers: {\n req: (req: any) => ({\n id: req.id,\n method: req.method,\n url: req.url,\n query: req.query,\n remoteAddress: req.remoteAddress,\n }),\n res: (res: any) => ({\n statusCode: res.statusCode,\n }),\n },\n\n transport: isProduction\n ? undefined // JSON to stdout – consumed by log aggregators\n : {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'SYS:HH:MM:ss.l',\n ignore: 'pid,hostname',\n singleLine: false,\n },\n },\n },\n };\n },\n inject: [ConfigService],\n }),\n ],\n providers: [AppLoggerService],\n exports: [PinoLoggerModule, AppLoggerService],\n})\nexport class AppLoggerModule {}\n`);\n\n // ── logger.service.ts ───────────────────────────────────────────────────\n await writeFile(path.join(loggerDir, 'logger.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { PinoLogger, InjectPinoLogger } from 'nestjs-pino';\n\n/**\n * Thin wrapper around PinoLogger that provides a stable application-level\n * logging interface. Inject this service where you need structured logging\n * with automatic request-id correlation (when called within an HTTP context).\n *\n * Usage:\n * constructor(private readonly logger: AppLoggerService) {}\n * this.logger.info({ orderId: '123' }, 'Order created');\n */\n@Injectable()\nexport class AppLoggerService {\n constructor(\n @InjectPinoLogger(AppLoggerService.name)\n private readonly logger: PinoLogger,\n ) {}\n\n trace(obj: object, msg?: string): void;\n trace(msg: string): void;\n trace(objOrMsg: object | string, msg?: string): void {\n if (typeof objOrMsg === 'string') {\n this.logger.trace(objOrMsg);\n } else {\n this.logger.trace(objOrMsg, msg);\n }\n }\n\n debug(obj: object, msg?: string): void;\n debug(msg: string): void;\n debug(objOrMsg: object | string, msg?: string): void {\n if (typeof objOrMsg === 'string') {\n this.logger.debug(objOrMsg);\n } else {\n this.logger.debug(objOrMsg, msg);\n }\n }\n\n info(obj: object, msg?: string): void;\n info(msg: string): void;\n info(objOrMsg: object | string, msg?: string): void {\n if (typeof objOrMsg === 'string') {\n this.logger.info(objOrMsg);\n } else {\n this.logger.info(objOrMsg, msg);\n }\n }\n\n warn(obj: object, msg?: string): void;\n warn(msg: string): void;\n warn(objOrMsg: object | string, msg?: string): void {\n if (typeof objOrMsg === 'string') {\n this.logger.warn(objOrMsg);\n } else {\n this.logger.warn(objOrMsg, msg);\n }\n }\n\n error(obj: object, msg?: string): void;\n error(msg: string): void;\n error(objOrMsg: object | string, msg?: string): void {\n if (typeof objOrMsg === 'string') {\n this.logger.error(objOrMsg);\n } else {\n this.logger.error(objOrMsg, msg);\n }\n }\n\n fatal(obj: object, msg?: string): void;\n fatal(msg: string): void;\n fatal(objOrMsg: object | string, msg?: string): void {\n if (typeof objOrMsg === 'string') {\n this.logger.fatal(objOrMsg);\n } else {\n this.logger.fatal(objOrMsg, msg);\n }\n }\n\n /** Create a child logger with persistent bindings (e.g. { module: 'billing' }) */\n child(bindings: Record<string, unknown>): AppLoggerService {\n // PinoLogger.assign merges bindings into the current context.\n // For a true child you can also use the raw pino instance.\n this.logger.assign(bindings);\n return this;\n }\n}\n`);\n\n dependencies['nestjs-pino'] = deps['nestjs-pino'];\n dependencies['pino'] = deps.pino;\n dependencies['pino-pretty'] = deps['pino-pretty'];\n dependencies['pino-http'] = deps['pino-http'];\n}\n\n// ---------------------------------------------------------------------------\n// Express – pino-http middleware with request-id correlation\n// ---------------------------------------------------------------------------\nasync function installExpressLogger(\n apiDir: string,\n dependencies: Record<string, string>,\n) {\n const middlewareDir = path.join(apiDir, 'src', 'middlewares');\n await ensureDir(middlewareDir);\n\n await writeFile(path.join(middlewareDir, 'logger.ts'), `import pino from 'pino';\nimport pinoHttp from 'pino-http';\nimport crypto from 'crypto';\nimport type { Request, Response, NextFunction } from 'express';\n\n// ── Base pino instance ─────────────────────────────────────────────────────\nconst isProduction = process.env.NODE_ENV === 'production';\n\nexport const logger = pino({\n level: process.env.LOG_LEVEL || 'info',\n ...(isProduction\n ? {} // JSON to stdout – ready for ELK / Datadog / CloudWatch\n : {\n transport: {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'SYS:HH:MM:ss.l',\n ignore: 'pid,hostname',\n singleLine: false,\n },\n },\n }),\n});\n\n// ── HTTP middleware ─────────────────────────────────────────────────────────\nexport const httpLogger = pinoHttp({\n logger,\n\n // Propagate or generate a request ID for end-to-end correlation\n genReqId: (req: any) =>\n (req.headers['x-request-id'] as string) ?? crypto.randomUUID(),\n\n // Custom log level based on response status code\n customLogLevel: (_req: any, res: any, err: any) => {\n if (res.statusCode >= 500 || err) return 'error';\n if (res.statusCode >= 400) return 'warn';\n return 'info';\n },\n\n // Add response-time to the log entry automatically\n customSuccessMessage: (req: any, res: any) => {\n return \\`\\${req.method} \\${req.url} completed with \\${res.statusCode}\\`;\n },\n\n customErrorMessage: (req: any, _res: any, err: any) => {\n return \\`\\${req.method} \\${req.url} errored: \\${err.message}\\`;\n },\n\n // Redact sensitive headers\n redact: {\n paths: [\n 'req.headers.authorization',\n 'req.headers.cookie',\n ],\n censor: '[REDACTED]',\n },\n\n // Keep serialized objects lean\n serializers: {\n req: (req: any) => ({\n id: req.id,\n method: req.method,\n url: req.url,\n query: req.query,\n remoteAddress: req.remoteAddress,\n }),\n res: (res: any) => ({\n statusCode: res.statusCode,\n }),\n },\n});\n\n/**\n * Express middleware that attaches the request ID to the response header\n * so clients and upstream services can use it for correlation.\n *\n * Usage:\n * app.use(requestIdMiddleware);\n * app.use(httpLogger);\n */\nexport function requestIdMiddleware(req: Request, res: Response, next: NextFunction) {\n const requestId = (req.headers['x-request-id'] as string) || crypto.randomUUID();\n req.headers['x-request-id'] = requestId;\n res.setHeader('x-request-id', requestId);\n next();\n}\n`);\n\n dependencies['pino'] = deps.pino;\n dependencies['pino-pretty'] = deps['pino-pretty'];\n dependencies['pino-http'] = deps['pino-http'];\n}\n\n// ---------------------------------------------------------------------------\n// Fastify – pino config object for the Fastify constructor\n// ---------------------------------------------------------------------------\nasync function installFastifyLogger(\n apiDir: string,\n dependencies: Record<string, string>,\n) {\n const configDir = path.join(apiDir, 'src', 'config');\n await ensureDir(configDir);\n\n await writeFile(path.join(configDir, 'logger.ts'), `import type { FastifyServerOptions } from 'fastify';\nimport crypto from 'crypto';\n\n/**\n * Pino logger configuration for the Fastify constructor.\n *\n * Fastify uses pino natively – no extra middleware needed.\n * Pass this to the Fastify factory:\n *\n * import Fastify from 'fastify';\n * import { loggerConfig } from './config/logger.js';\n *\n * const app = Fastify({ ...loggerConfig });\n */\n\nconst isProduction = process.env.NODE_ENV === 'production';\n\nexport const loggerConfig: Pick<FastifyServerOptions, 'logger' | 'genReqId' | 'requestIdHeader'> = {\n // Tell Fastify which header carries an upstream request ID\n requestIdHeader: 'x-request-id',\n\n // Generate a UUID when no upstream ID is present\n genReqId: (req) =>\n (req.headers['x-request-id'] as string) ?? crypto.randomUUID(),\n\n logger: {\n level: process.env.LOG_LEVEL || 'info',\n\n // Redact sensitive headers\n redact: {\n paths: [\n 'req.headers.authorization',\n 'req.headers.cookie',\n ],\n censor: '[REDACTED]',\n },\n\n // Lean serializers\n serializers: {\n req: (req: any) => ({\n id: req.id,\n method: req.method,\n url: req.url,\n query: req.query,\n remoteAddress: req.ip,\n }),\n res: (res: any) => ({\n statusCode: res.statusCode,\n }),\n },\n\n // Pretty-print in development, structured JSON in production\n ...(isProduction\n ? {}\n : {\n transport: {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'SYS:HH:MM:ss.l',\n ignore: 'pid,hostname',\n singleLine: false,\n },\n },\n }),\n },\n};\n`);\n\n dependencies['pino'] = deps.pino;\n dependencies['pino-pretty'] = deps['pino-pretty'];\n}\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const swaggerInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies, devDependencies } = opts;\n\n const projectName = config.projectName;\n\n if (config.backend === 'nestjs') {\n // ── NestJS: src/common/swagger/swagger.config.ts ──\n await ensureDir(path.join(apiDir, 'src', 'common', 'swagger'));\n\n await writeFile(path.join(apiDir, 'src', 'common', 'swagger', 'swagger.config.ts'), `import { INestApplication } from '@nestjs/common';\nimport { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';\n\n/**\n * Configures Swagger / OpenAPI documentation for the NestJS application.\n * Accessible at /api/docs once the app is running.\n */\nexport function setupSwagger(app: INestApplication): void {\n const config = new DocumentBuilder()\n .setTitle('${projectName}')\n .setDescription('API documentation for ${projectName}')\n .setVersion('1.0')\n .addBearerAuth(\n {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n name: 'Authorization',\n description: 'Enter your JWT token',\n in: 'header',\n },\n 'access-token',\n )\n .addTag('health', 'Health check endpoints')\n .addTag('auth', 'Authentication endpoints')\n .addTag('users', 'User management endpoints')\n .build();\n\n const document = SwaggerModule.createDocument(app, config);\n\n SwaggerModule.setup('api/docs', app, document, {\n swaggerOptions: {\n persistAuthorization: true,\n docExpansion: 'none',\n filter: true,\n showRequestDuration: true,\n syntaxHighlight: {\n activate: true,\n theme: 'monokai',\n },\n },\n customSiteTitle: '${projectName} - API Docs',\n });\n}\n`);\n\n dependencies['@nestjs/swagger'] = deps['@nestjs/swagger'];\n\n } else if (config.backend === 'express') {\n // ── Express: src/config/swagger.ts ──\n await ensureDir(path.join(apiDir, 'src', 'config'));\n\n await writeFile(path.join(apiDir, 'src', 'config', 'swagger.ts'), `import type { Express } from 'express';\nimport swaggerJsdoc from 'swagger-jsdoc';\nimport swaggerUi from 'swagger-ui-express';\n\n/**\n * Swagger / OpenAPI configuration for Express.\n *\n * Route handlers are documented using JSDoc comments with the @openapi tag.\n * Example:\n *\n * \\`\\`\\`ts\n * /**\n * * @openapi\n * * /api/health:\n * * get:\n * * tags:\n * * - health\n * * summary: Health check\n * * responses:\n * * 200:\n * * description: Service is healthy\n * * content:\n * * application/json:\n * * schema:\n * * type: object\n * * properties:\n * * status:\n * * type: string\n * * example: ok\n * * /\n * \\`\\`\\`\n */\n\nconst swaggerDefinition: swaggerJsdoc.Options['definition'] = {\n openapi: '3.0.3',\n info: {\n title: '${projectName}',\n description: 'API documentation for ${projectName}',\n version: '1.0.0',\n contact: {\n name: 'API Support',\n },\n },\n servers: [\n {\n url: process.env.API_URL || 'http://localhost:{port}',\n description: 'API Server',\n variables: {\n port: {\n default: process.env.PORT || '3000',\n },\n },\n },\n ],\n components: {\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: 'Enter your JWT token',\n },\n },\n },\n tags: [\n { name: 'health', description: 'Health check endpoints' },\n { name: 'auth', description: 'Authentication endpoints' },\n { name: 'users', description: 'User management endpoints' },\n ],\n};\n\nconst swaggerOptions: swaggerJsdoc.Options = {\n definition: swaggerDefinition,\n // Scan route files for @openapi JSDoc comments\n apis: [\n './src/routes/**/*.ts',\n './src/routes/**/*.js',\n './src/**/*.routes.ts',\n './src/**/*.routes.js',\n ],\n};\n\nconst swaggerSpec = swaggerJsdoc(swaggerOptions);\n\n/**\n * Sets up Swagger UI middleware on the Express app.\n * Documentation is served at /api/docs.\n */\nexport function setupSwagger(app: Express): void {\n app.use(\n '/api/docs',\n swaggerUi.serve,\n swaggerUi.setup(swaggerSpec, {\n swaggerOptions: {\n persistAuthorization: true,\n docExpansion: 'none',\n filter: true,\n showRequestDuration: true,\n syntaxHighlight: {\n activate: true,\n theme: 'monokai',\n },\n },\n customSiteTitle: '${projectName} - API Docs',\n }),\n );\n\n // Expose raw OpenAPI spec as JSON\n app.get('/api/docs/json', (_req, res) => {\n res.setHeader('Content-Type', 'application/json');\n res.send(swaggerSpec);\n });\n}\n`);\n\n dependencies['swagger-jsdoc'] = deps['swagger-jsdoc'];\n dependencies['swagger-ui-express'] = deps['swagger-ui-express'];\n devDependencies['@types/swagger-jsdoc'] = deps['@types/swagger-jsdoc'];\n devDependencies['@types/swagger-ui-express'] = deps['@types/swagger-ui-express'];\n\n } else {\n // ── Fastify: src/plugins/swagger.ts ──\n await ensureDir(path.join(apiDir, 'src', 'plugins'));\n\n await writeFile(path.join(apiDir, 'src', 'plugins', 'swagger.ts'), `import type { FastifyInstance } from 'fastify';\nimport fp from 'fastify-plugin';\nimport swagger from '@fastify/swagger';\nimport swaggerUi from '@fastify/swagger-ui';\n\n/**\n * Fastify plugin that registers @fastify/swagger and @fastify/swagger-ui.\n * Documentation is served at /api/docs.\n */\nasync function swaggerPlugin(app: FastifyInstance): Promise<void> {\n await app.register(swagger, {\n openapi: {\n openapi: '3.0.3',\n info: {\n title: '${projectName}',\n description: 'API documentation for ${projectName}',\n version: '1.0.0',\n },\n servers: [\n {\n url: process.env.API_URL || 'http://localhost:{port}',\n description: 'API Server',\n variables: {\n port: {\n default: process.env.PORT || '3000',\n },\n },\n },\n ],\n components: {\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: 'Enter your JWT token',\n },\n },\n },\n tags: [\n { name: 'health', description: 'Health check endpoints' },\n { name: 'auth', description: 'Authentication endpoints' },\n { name: 'users', description: 'User management endpoints' },\n ],\n },\n });\n\n await app.register(swaggerUi, {\n routePrefix: '/api/docs',\n uiConfig: {\n persistAuthorization: true,\n docExpansion: 'none',\n filter: true,\n showRequestDuration: true,\n syntaxHighlight: {\n activate: true,\n theme: 'monokai',\n },\n },\n staticCSP: true,\n transformStaticCSP: (header: string) => header,\n });\n}\n\nexport default fp(swaggerPlugin, {\n name: 'swagger',\n fastify: '5.x',\n});\n`);\n\n dependencies['@fastify/swagger'] = deps['@fastify/swagger'];\n dependencies['@fastify/swagger-ui'] = deps['@fastify/swagger-ui'];\n }\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const rbacInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n const rbacDir = path.join(apiDir, 'src', 'rbac');\n await ensureDir(rbacDir);\n\n // ── Dependencies ─────────────────────────────────────────────────────\n dependencies['@casl/ability'] = deps['@casl/ability'];\n if (config.usePrisma) {\n dependencies['@casl/prisma'] = deps['@casl/prisma'];\n }\n\n // ── NestJS ───────────────────────────────────────────────────────────\n if (config.backend === 'nestjs') {\n await writeNestjsFiles(rbacDir, config.usePrisma);\n }\n\n // ── Express ──────────────────────────────────────────────────────────\n if (config.backend === 'express') {\n await writeExpressFiles(rbacDir, config.usePrisma);\n }\n\n // ── Fastify ──────────────────────────────────────────────────────────\n if (config.backend === 'fastify') {\n await writeFastifyFiles(rbacDir, config.usePrisma);\n }\n};\n\n// ═══════════════════════════════════════════════════════════════════════════\n// NestJS\n// ═══════════════════════════════════════════════════════════════════════════\n\nasync function writeNestjsFiles(rbacDir: string, usePrisma: boolean) {\n // roles.enum.ts\n await writeFile(path.join(rbacDir, 'roles.enum.ts'), `export enum Role {\n ADMIN = 'admin',\n USER = 'user',\n OWNER = 'owner',\n}\n`);\n\n // roles.decorator.ts\n await writeFile(path.join(rbacDir, 'roles.decorator.ts'), `import { SetMetadata } from '@nestjs/common';\nimport { Role } from './roles.enum';\n\nexport const ROLES_KEY = 'roles';\nexport const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);\n`);\n\n // roles.guard.ts\n await writeFile(path.join(rbacDir, 'roles.guard.ts'), `import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { Role } from './roles.enum';\nimport { ROLES_KEY } from './roles.decorator';\n\n@Injectable()\nexport class RolesGuard implements CanActivate {\n constructor(private reflector: Reflector) {}\n\n canActivate(context: ExecutionContext): boolean {\n const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n\n if (!requiredRoles || requiredRoles.length === 0) {\n return true;\n }\n\n const { user } = context.switchToHttp().getRequest();\n\n if (!user || !user.role) {\n throw new ForbiddenException('User role not found in request');\n }\n\n const hasRole = requiredRoles.some((role) => user.role === role);\n\n if (!hasRole) {\n throw new ForbiddenException(\n \\`Insufficient permissions. Required: \\${requiredRoles.join(', ')}\\`,\n );\n }\n\n return true;\n }\n}\n`);\n\n // abilities.factory.ts\n const abilitiesImport = usePrisma\n ? `import { AbilityBuilder, PureAbility } from '@casl/ability';\nimport { createPrismaAbility, PrismaQuery, Subjects } from '@casl/prisma';`\n : `import { AbilityBuilder, createMongoAbility, MongoAbility } from '@casl/ability';`;\n\n const abilitiesContent = usePrisma\n ? `import { Injectable } from '@nestjs/common';\n${abilitiesImport}\nimport { Role } from './roles.enum';\n\n// Define the subject types that match your Prisma models.\n// Extend this union as you add more models.\ntype AppSubjects = 'User' | 'Post' | 'Organization' | 'all';\n\ntype AppAbility = PureAbility<[string, AppSubjects], PrismaQuery>;\n\nexport type { AppAbility };\n\nexport interface UserContext {\n id: string;\n role: Role;\n organizationId?: string;\n}\n\n@Injectable()\nexport class AbilitiesFactory {\n /**\n * Build CASL abilities for a given user context.\n * This factory centralises all permission logic so guards,\n * services and controllers can reuse it.\n */\n createForUser(user: UserContext): AppAbility {\n const builder = new AbilityBuilder<AppAbility>(createPrismaAbility);\n const { can, cannot, build } = builder;\n\n switch (user.role) {\n case Role.ADMIN:\n // Admins can do everything\n can('manage', 'all');\n break;\n\n case Role.OWNER:\n // Owners can manage their own organization and its resources\n can('manage', 'Organization', { id: user.organizationId });\n can('read', 'Organization');\n can('manage', 'Post', { organizationId: user.organizationId });\n can('manage', 'User', { organizationId: user.organizationId });\n // Owners cannot delete other owners or admins\n cannot('delete', 'User', { role: { in: [Role.ADMIN, Role.OWNER] } });\n // But they can always manage their own profile\n can('manage', 'User', { id: user.id });\n break;\n\n case Role.USER:\n // Regular users can read organizations they belong to\n can('read', 'Organization', { id: user.organizationId });\n // They can manage their own profile\n can('read', 'User', { id: user.id });\n can('update', 'User', { id: user.id });\n // They can create posts and manage their own\n can('create', 'Post');\n can('read', 'Post', { organizationId: user.organizationId });\n can('update', 'Post', { authorId: user.id });\n can('delete', 'Post', { authorId: user.id });\n break;\n\n default:\n // No permissions by default\n break;\n }\n\n return build();\n }\n}\n`\n : `import { Injectable } from '@nestjs/common';\n${abilitiesImport}\nimport { Role } from './roles.enum';\n\ntype Actions = 'manage' | 'create' | 'read' | 'update' | 'delete';\ntype Subjects = 'User' | 'Post' | 'Organization' | 'all';\n\ntype AppAbility = MongoAbility<[Actions, Subjects]>;\n\nexport type { AppAbility };\n\nexport interface UserContext {\n id: string;\n role: Role;\n organizationId?: string;\n}\n\n@Injectable()\nexport class AbilitiesFactory {\n /**\n * Build CASL abilities for a given user context.\n * This factory centralises all permission logic so guards,\n * services and controllers can reuse it.\n */\n createForUser(user: UserContext): AppAbility {\n const { can, cannot, build } = new AbilityBuilder<AppAbility>(createMongoAbility);\n\n switch (user.role) {\n case Role.ADMIN:\n // Admins can do everything\n can('manage', 'all');\n break;\n\n case Role.OWNER:\n // Owners can manage their own organization and its resources\n can('manage', 'Organization', { id: user.organizationId });\n can('read', 'Organization');\n can('manage', 'Post', { organizationId: user.organizationId });\n can('manage', 'User', { organizationId: user.organizationId });\n // Owners cannot delete other owners or admins\n cannot('delete', 'User', { role: { $in: [Role.ADMIN, Role.OWNER] } });\n // But they can always manage their own profile\n can('manage', 'User', { id: user.id });\n break;\n\n case Role.USER:\n // Regular users can read organizations they belong to\n can('read', 'Organization', { id: user.organizationId });\n // They can manage their own profile\n can('read', 'User', { id: user.id });\n can('update', 'User', { id: user.id });\n // They can create posts and manage their own\n can('create', 'Post');\n can('read', 'Post', { organizationId: user.organizationId });\n can('update', 'Post', { authorId: user.id });\n can('delete', 'Post', { authorId: user.id });\n break;\n\n default:\n // No permissions by default\n break;\n }\n\n return build();\n }\n}\n`;\n\n await writeFile(path.join(rbacDir, 'abilities.factory.ts'), abilitiesContent);\n\n // rbac.module.ts\n await writeFile(path.join(rbacDir, 'rbac.module.ts'), `import { Module, Global } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { RolesGuard } from './roles.guard';\nimport { AbilitiesFactory } from './abilities.factory';\n\n@Global()\n@Module({\n providers: [\n AbilitiesFactory,\n {\n provide: APP_GUARD,\n useClass: RolesGuard,\n },\n ],\n exports: [AbilitiesFactory],\n})\nexport class RbacModule {}\n`);\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Express\n// ═══════════════════════════════════════════════════════════════════════════\n\nasync function writeExpressFiles(rbacDir: string, usePrisma: boolean) {\n // roles.ts\n await writeFile(path.join(rbacDir, 'roles.ts'), `export enum Role {\n ADMIN = 'admin',\n USER = 'user',\n OWNER = 'owner',\n}\n`);\n\n // rbac.middleware.ts\n await writeFile(path.join(rbacDir, 'rbac.middleware.ts'), `import type { Request, Response, NextFunction } from 'express';\nimport { Role } from './roles.js';\n\n/**\n * Middleware factory that restricts access to users with specific roles.\n * Assumes req.user has been populated by an auth middleware upstream.\n *\n * Usage:\n * router.delete('/users/:id', requireRole(Role.ADMIN, Role.OWNER), handler);\n */\nexport function requireRole(...roles: Role[]) {\n return (req: Request, res: Response, next: NextFunction) => {\n const user = (req as any).user;\n\n if (!user || !user.role) {\n return res.status(403).json({ error: 'User role not found in request' });\n }\n\n if (!roles.includes(user.role)) {\n return res.status(403).json({\n error: \\`Insufficient permissions. Required: \\${roles.join(', ')}\\`,\n });\n }\n\n next();\n };\n}\n`);\n\n // abilities.ts\n const abilitiesImport = usePrisma\n ? `import { AbilityBuilder, PureAbility } from '@casl/ability';\nimport { createPrismaAbility, PrismaQuery, Subjects } from '@casl/prisma';`\n : `import { AbilityBuilder, createMongoAbility, MongoAbility } from '@casl/ability';`;\n\n const abilitiesContent = usePrisma\n ? `${abilitiesImport}\nimport { Role } from './roles.js';\n\n// Define the subject types that match your Prisma models.\n// Extend this union as you add more models.\ntype AppSubjects = 'User' | 'Post' | 'Organization' | 'all';\n\ntype AppAbility = PureAbility<[string, AppSubjects], PrismaQuery>;\n\nexport type { AppAbility };\n\nexport interface UserContext {\n id: string;\n role: Role;\n organizationId?: string;\n}\n\n/**\n * Build CASL abilities for a given user context.\n * Import and call this wherever you need fine-grained permission checks.\n *\n * Example:\n * const ability = defineAbilitiesFor(req.user);\n * if (ability.can('update', subject('Post', post))) { ... }\n */\nexport function defineAbilitiesFor(user: UserContext): AppAbility {\n const builder = new AbilityBuilder<AppAbility>(createPrismaAbility);\n const { can, cannot, build } = builder;\n\n switch (user.role) {\n case Role.ADMIN:\n // Admins can do everything\n can('manage', 'all');\n break;\n\n case Role.OWNER:\n // Owners can manage their own organization and its resources\n can('manage', 'Organization', { id: user.organizationId });\n can('read', 'Organization');\n can('manage', 'Post', { organizationId: user.organizationId });\n can('manage', 'User', { organizationId: user.organizationId });\n // Owners cannot delete other owners or admins\n cannot('delete', 'User', { role: { in: [Role.ADMIN, Role.OWNER] } });\n // But they can always manage their own profile\n can('manage', 'User', { id: user.id });\n break;\n\n case Role.USER:\n // Regular users can read organizations they belong to\n can('read', 'Organization', { id: user.organizationId });\n // They can manage their own profile\n can('read', 'User', { id: user.id });\n can('update', 'User', { id: user.id });\n // They can create posts and manage their own\n can('create', 'Post');\n can('read', 'Post', { organizationId: user.organizationId });\n can('update', 'Post', { authorId: user.id });\n can('delete', 'Post', { authorId: user.id });\n break;\n\n default:\n // No permissions by default\n break;\n }\n\n return build();\n}\n`\n : `${abilitiesImport}\nimport { Role } from './roles.js';\n\ntype Actions = 'manage' | 'create' | 'read' | 'update' | 'delete';\ntype Subjects = 'User' | 'Post' | 'Organization' | 'all';\n\ntype AppAbility = MongoAbility<[Actions, Subjects]>;\n\nexport type { AppAbility };\n\nexport interface UserContext {\n id: string;\n role: Role;\n organizationId?: string;\n}\n\n/**\n * Build CASL abilities for a given user context.\n * Import and call this wherever you need fine-grained permission checks.\n *\n * Example:\n * const ability = defineAbilitiesFor(req.user);\n * if (ability.can('update', subject('Post', post))) { ... }\n */\nexport function defineAbilitiesFor(user: UserContext): AppAbility {\n const { can, cannot, build } = new AbilityBuilder<AppAbility>(createMongoAbility);\n\n switch (user.role) {\n case Role.ADMIN:\n // Admins can do everything\n can('manage', 'all');\n break;\n\n case Role.OWNER:\n // Owners can manage their own organization and its resources\n can('manage', 'Organization', { id: user.organizationId });\n can('read', 'Organization');\n can('manage', 'Post', { organizationId: user.organizationId });\n can('manage', 'User', { organizationId: user.organizationId });\n // Owners cannot delete other owners or admins\n cannot('delete', 'User', { role: { $in: [Role.ADMIN, Role.OWNER] } });\n // But they can always manage their own profile\n can('manage', 'User', { id: user.id });\n break;\n\n case Role.USER:\n // Regular users can read organizations they belong to\n can('read', 'Organization', { id: user.organizationId });\n // They can manage their own profile\n can('read', 'User', { id: user.id });\n can('update', 'User', { id: user.id });\n // They can create posts and manage their own\n can('create', 'Post');\n can('read', 'Post', { organizationId: user.organizationId });\n can('update', 'Post', { authorId: user.id });\n can('delete', 'Post', { authorId: user.id });\n break;\n\n default:\n // No permissions by default\n break;\n }\n\n return build();\n}\n`;\n\n await writeFile(path.join(rbacDir, 'abilities.ts'), abilitiesContent);\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Fastify\n// ═══════════════════════════════════════════════════════════════════════════\n\nasync function writeFastifyFiles(rbacDir: string, usePrisma: boolean) {\n // roles.ts\n await writeFile(path.join(rbacDir, 'roles.ts'), `export enum Role {\n ADMIN = 'admin',\n USER = 'user',\n OWNER = 'owner',\n}\n`);\n\n // rbac.hook.ts\n await writeFile(path.join(rbacDir, 'rbac.hook.ts'), `import type { FastifyRequest, FastifyReply } from 'fastify';\nimport { Role } from './roles.js';\n\n/**\n * Fastify preHandler hook factory that restricts access to users with\n * specific roles. Assumes request.user has been populated by an auth\n * hook upstream.\n *\n * Usage:\n * app.delete('/users/:id', { preHandler: [requireRole(Role.ADMIN, Role.OWNER)] }, handler);\n */\nexport function requireRole(...roles: Role[]) {\n return async (request: FastifyRequest, reply: FastifyReply) => {\n const user = (request as any).user;\n\n if (!user || !user.role) {\n return reply.status(403).send({ error: 'User role not found in request' });\n }\n\n if (!roles.includes(user.role)) {\n return reply.status(403).send({\n error: \\`Insufficient permissions. Required: \\${roles.join(', ')}\\`,\n });\n }\n };\n}\n`);\n\n // abilities.ts\n const abilitiesImport = usePrisma\n ? `import { AbilityBuilder, PureAbility } from '@casl/ability';\nimport { createPrismaAbility, PrismaQuery, Subjects } from '@casl/prisma';`\n : `import { AbilityBuilder, createMongoAbility, MongoAbility } from '@casl/ability';`;\n\n const abilitiesContent = usePrisma\n ? `${abilitiesImport}\nimport { Role } from './roles.js';\n\n// Define the subject types that match your Prisma models.\n// Extend this union as you add more models.\ntype AppSubjects = 'User' | 'Post' | 'Organization' | 'all';\n\ntype AppAbility = PureAbility<[string, AppSubjects], PrismaQuery>;\n\nexport type { AppAbility };\n\nexport interface UserContext {\n id: string;\n role: Role;\n organizationId?: string;\n}\n\n/**\n * Build CASL abilities for a given user context.\n * Import and call this wherever you need fine-grained permission checks.\n *\n * Example:\n * const ability = defineAbilitiesFor(request.user);\n * if (ability.can('update', subject('Post', post))) { ... }\n */\nexport function defineAbilitiesFor(user: UserContext): AppAbility {\n const builder = new AbilityBuilder<AppAbility>(createPrismaAbility);\n const { can, cannot, build } = builder;\n\n switch (user.role) {\n case Role.ADMIN:\n // Admins can do everything\n can('manage', 'all');\n break;\n\n case Role.OWNER:\n // Owners can manage their own organization and its resources\n can('manage', 'Organization', { id: user.organizationId });\n can('read', 'Organization');\n can('manage', 'Post', { organizationId: user.organizationId });\n can('manage', 'User', { organizationId: user.organizationId });\n // Owners cannot delete other owners or admins\n cannot('delete', 'User', { role: { in: [Role.ADMIN, Role.OWNER] } });\n // But they can always manage their own profile\n can('manage', 'User', { id: user.id });\n break;\n\n case Role.USER:\n // Regular users can read organizations they belong to\n can('read', 'Organization', { id: user.organizationId });\n // They can manage their own profile\n can('read', 'User', { id: user.id });\n can('update', 'User', { id: user.id });\n // They can create posts and manage their own\n can('create', 'Post');\n can('read', 'Post', { organizationId: user.organizationId });\n can('update', 'Post', { authorId: user.id });\n can('delete', 'Post', { authorId: user.id });\n break;\n\n default:\n // No permissions by default\n break;\n }\n\n return build();\n}\n`\n : `${abilitiesImport}\nimport { Role } from './roles.js';\n\ntype Actions = 'manage' | 'create' | 'read' | 'update' | 'delete';\ntype Subjects = 'User' | 'Post' | 'Organization' | 'all';\n\ntype AppAbility = MongoAbility<[Actions, Subjects]>;\n\nexport type { AppAbility };\n\nexport interface UserContext {\n id: string;\n role: Role;\n organizationId?: string;\n}\n\n/**\n * Build CASL abilities for a given user context.\n * Import and call this wherever you need fine-grained permission checks.\n *\n * Example:\n * const ability = defineAbilitiesFor(request.user);\n * if (ability.can('update', subject('Post', post))) { ... }\n */\nexport function defineAbilitiesFor(user: UserContext): AppAbility {\n const { can, cannot, build } = new AbilityBuilder<AppAbility>(createMongoAbility);\n\n switch (user.role) {\n case Role.ADMIN:\n // Admins can do everything\n can('manage', 'all');\n break;\n\n case Role.OWNER:\n // Owners can manage their own organization and its resources\n can('manage', 'Organization', { id: user.organizationId });\n can('read', 'Organization');\n can('manage', 'Post', { organizationId: user.organizationId });\n can('manage', 'User', { organizationId: user.organizationId });\n // Owners cannot delete other owners or admins\n cannot('delete', 'User', { role: { $in: [Role.ADMIN, Role.OWNER] } });\n // But they can always manage their own profile\n can('manage', 'User', { id: user.id });\n break;\n\n case Role.USER:\n // Regular users can read organizations they belong to\n can('read', 'Organization', { id: user.organizationId });\n // They can manage their own profile\n can('read', 'User', { id: user.id });\n can('update', 'User', { id: user.id });\n // They can create posts and manage their own\n can('create', 'Post');\n can('read', 'Post', { organizationId: user.organizationId });\n can('update', 'Post', { authorId: user.id });\n can('delete', 'Post', { authorId: user.id });\n break;\n\n default:\n // No permissions by default\n break;\n }\n\n return build();\n}\n`;\n\n await writeFile(path.join(rbacDir, 'abilities.ts'), abilitiesContent);\n}\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\n\nexport const organizationsInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries } = opts;\n\n const orgDir = path.join(apiDir, 'src', 'organizations');\n await ensureDir(orgDir);\n\n envEntries.push({\n key: 'APP_URL',\n value: 'http://localhost:3000',\n category: 'Organizations',\n comment: 'Base URL for invite links',\n });\n\n // ──────────────────────────────────────────────\n // NestJS backend\n // ──────────────────────────────────────────────\n if (config.backend === 'nestjs') {\n // ── DTOs ──\n await ensureDir(path.join(orgDir, 'dto'));\n\n await writeFile(path.join(orgDir, 'dto', 'create-organization.dto.ts'), `export class CreateOrganizationDto {\n name: string;\n slug?: string;\n description?: string;\n}\n\nexport class UpdateOrganizationDto {\n name?: string;\n description?: string;\n}\n\nexport class InviteMemberDto {\n email: string;\n role?: 'admin' | 'member';\n}\n`);\n\n // ── Service ──\n await writeFile(path.join(orgDir, 'organizations.service.ts'), `import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport type { CreateOrganizationDto, UpdateOrganizationDto, InviteMemberDto } from './dto/create-organization.dto';\n\nexport type OrgRole = 'owner' | 'admin' | 'member';\n\nexport interface Organization {\n id: string;\n name: string;\n slug: string;\n description?: string;\n createdAt: Date;\n}\n\nexport interface OrgMember {\n id: string;\n userId: string;\n email: string;\n orgId: string;\n role: OrgRole;\n joinedAt: Date;\n}\n\n@Injectable()\nexport class OrganizationsService {\n constructor(private configService: ConfigService) {}\n\n async create(dto: CreateOrganizationDto, ownerId: string): Promise<Organization> {\n const slug = dto.slug || this.generateSlug(dto.name);\n\n // TODO: Persist organization to database\n const org: Organization = {\n id: 'org-' + Date.now(),\n name: dto.name,\n slug,\n description: dto.description,\n createdAt: new Date(),\n };\n\n // TODO: Create owner membership record\n // await this.addMember(org.id, ownerId, ownerEmail, 'owner');\n\n return org;\n }\n\n async findAll(userId: string): Promise<Organization[]> {\n // TODO: Query organizations where user is a member\n return [];\n }\n\n async findById(orgId: string, userId: string): Promise<Organization> {\n // TODO: Query organization by ID and verify user membership\n throw new NotFoundException(\\`Organization \\${orgId} not found\\`);\n }\n\n async update(orgId: string, dto: UpdateOrganizationDto, userId: string): Promise<Organization> {\n // TODO: Verify user has admin/owner role in org\n // TODO: Update organization in database\n throw new NotFoundException(\\`Organization \\${orgId} not found\\`);\n }\n\n async delete(orgId: string, userId: string): Promise<void> {\n // TODO: Verify user is owner of org\n // TODO: Delete organization and all memberships from database\n }\n\n async inviteMember(orgId: string, dto: InviteMemberDto, inviterId: string): Promise<{ inviteLink: string }> {\n // TODO: Verify inviter has admin/owner role in org\n // TODO: Check if user is already a member\n\n const role = dto.role || 'member';\n const appUrl = this.configService.get<string>('APP_URL', 'http://localhost:3000');\n\n // TODO: Create pending invitation record in database\n const inviteToken = this.generateInviteToken();\n const inviteLink = \\`\\${appUrl}/invite/\\${inviteToken}\\`;\n\n // TODO: Send invitation email to dto.email with inviteLink\n\n return { inviteLink };\n }\n\n async acceptInvite(inviteToken: string, userId: string): Promise<OrgMember> {\n // TODO: Look up invitation by token, verify it is not expired\n // TODO: Create membership record for the user\n // TODO: Mark invitation as accepted\n throw new NotFoundException('Invalid or expired invite token');\n }\n\n async removeMember(orgId: string, memberId: string, removerId: string): Promise<void> {\n // TODO: Verify remover has admin/owner role\n // TODO: Prevent removing the last owner\n // TODO: Delete membership record from database\n }\n\n async listMembers(orgId: string, userId: string): Promise<OrgMember[]> {\n // TODO: Verify user is a member of the org\n // TODO: Query all members for the org\n return [];\n }\n\n async updateMemberRole(orgId: string, memberId: string, role: OrgRole, updaterId: string): Promise<OrgMember> {\n // TODO: Verify updater is owner (only owners can change roles)\n // TODO: Prevent demoting the last owner\n // TODO: Update membership role in database\n throw new NotFoundException(\\`Member \\${memberId} not found\\`);\n }\n\n private generateSlug(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-|-$)/g, '');\n }\n\n private generateInviteToken(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n }\n}\n`);\n\n // ── Controller ──\n await writeFile(path.join(orgDir, 'organizations.controller.ts'), `import {\n Controller,\n Get,\n Post,\n Put,\n Delete,\n Body,\n Param,\n Req,\n UseGuards,\n HttpCode,\n HttpStatus,\n} from '@nestjs/common';\nimport { OrganizationsService } from './organizations.service';\nimport { CreateOrganizationDto, UpdateOrganizationDto, InviteMemberDto } from './dto/create-organization.dto';\n\n// TODO: Import your auth guard (e.g. JwtAuthGuard)\n// import { JwtAuthGuard } from '../auth/jwt-auth.guard';\n\n@Controller('organizations')\n// @UseGuards(JwtAuthGuard)\nexport class OrganizationsController {\n constructor(private readonly organizationsService: OrganizationsService) {}\n\n @Post()\n async create(@Body() dto: CreateOrganizationDto, @Req() req: any) {\n const userId = req.user?.id || req.user?.sub;\n return this.organizationsService.create(dto, userId);\n }\n\n @Get()\n async findAll(@Req() req: any) {\n const userId = req.user?.id || req.user?.sub;\n return this.organizationsService.findAll(userId);\n }\n\n @Get(':orgId')\n async findOne(@Param('orgId') orgId: string, @Req() req: any) {\n const userId = req.user?.id || req.user?.sub;\n return this.organizationsService.findById(orgId, userId);\n }\n\n @Put(':orgId')\n async update(\n @Param('orgId') orgId: string,\n @Body() dto: UpdateOrganizationDto,\n @Req() req: any,\n ) {\n const userId = req.user?.id || req.user?.sub;\n return this.organizationsService.update(orgId, dto, userId);\n }\n\n @Delete(':orgId')\n @HttpCode(HttpStatus.NO_CONTENT)\n async remove(@Param('orgId') orgId: string, @Req() req: any) {\n const userId = req.user?.id || req.user?.sub;\n return this.organizationsService.delete(orgId, userId);\n }\n\n @Post(':orgId/invite')\n async inviteMember(\n @Param('orgId') orgId: string,\n @Body() dto: InviteMemberDto,\n @Req() req: any,\n ) {\n const userId = req.user?.id || req.user?.sub;\n return this.organizationsService.inviteMember(orgId, dto, userId);\n }\n\n @Post('invite/:token/accept')\n async acceptInvite(@Param('token') token: string, @Req() req: any) {\n const userId = req.user?.id || req.user?.sub;\n return this.organizationsService.acceptInvite(token, userId);\n }\n\n @Delete(':orgId/members/:memberId')\n @HttpCode(HttpStatus.NO_CONTENT)\n async removeMember(\n @Param('orgId') orgId: string,\n @Param('memberId') memberId: string,\n @Req() req: any,\n ) {\n const userId = req.user?.id || req.user?.sub;\n return this.organizationsService.removeMember(orgId, memberId, userId);\n }\n\n @Get(':orgId/members')\n async listMembers(@Param('orgId') orgId: string, @Req() req: any) {\n const userId = req.user?.id || req.user?.sub;\n return this.organizationsService.listMembers(orgId, userId);\n }\n\n @Put(':orgId/members/:memberId/role')\n async updateMemberRole(\n @Param('orgId') orgId: string,\n @Param('memberId') memberId: string,\n @Body('role') role: 'owner' | 'admin' | 'member',\n @Req() req: any,\n ) {\n const userId = req.user?.id || req.user?.sub;\n return this.organizationsService.updateMemberRole(orgId, memberId, role, userId);\n }\n}\n`);\n\n // ── Module ──\n await writeFile(path.join(orgDir, 'organizations.module.ts'), `import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { OrganizationsController } from './organizations.controller';\nimport { OrganizationsService } from './organizations.service';\n\n@Module({\n imports: [ConfigModule],\n controllers: [OrganizationsController],\n providers: [OrganizationsService],\n exports: [OrganizationsService],\n})\nexport class OrganizationsModule {}\n`);\n\n // ──────────────────────────────────────────────\n // Express backend\n // ──────────────────────────────────────────────\n } else if (config.backend === 'express') {\n // ── Service ──\n await writeFile(path.join(orgDir, 'organizations.service.ts'), `export type OrgRole = 'owner' | 'admin' | 'member';\n\nexport interface Organization {\n id: string;\n name: string;\n slug: string;\n description?: string;\n createdAt: Date;\n}\n\nexport interface OrgMember {\n id: string;\n userId: string;\n email: string;\n orgId: string;\n role: OrgRole;\n joinedAt: Date;\n}\n\nfunction generateSlug(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-|-$)/g, '');\n}\n\nfunction generateInviteToken(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n}\n\nexport async function createOrganization(\n data: { name: string; slug?: string; description?: string },\n ownerId: string,\n): Promise<Organization> {\n const slug = data.slug || generateSlug(data.name);\n\n // TODO: Persist organization to database\n const org: Organization = {\n id: 'org-' + Date.now(),\n name: data.name,\n slug,\n description: data.description,\n createdAt: new Date(),\n };\n\n // TODO: Create owner membership record\n // await addMemberToOrg(org.id, ownerId, ownerEmail, 'owner');\n\n return org;\n}\n\nexport async function listOrganizations(userId: string): Promise<Organization[]> {\n // TODO: Query organizations where user is a member\n return [];\n}\n\nexport async function getOrganization(orgId: string, userId: string): Promise<Organization | null> {\n // TODO: Query organization by ID and verify user membership\n return null;\n}\n\nexport async function updateOrganization(\n orgId: string,\n data: { name?: string; description?: string },\n userId: string,\n): Promise<Organization | null> {\n // TODO: Verify user has admin/owner role in org\n // TODO: Update organization in database\n return null;\n}\n\nexport async function deleteOrganization(orgId: string, userId: string): Promise<boolean> {\n // TODO: Verify user is owner of org\n // TODO: Delete organization and all memberships from database\n return false;\n}\n\nexport async function inviteMember(\n orgId: string,\n data: { email: string; role?: 'admin' | 'member' },\n inviterId: string,\n): Promise<{ inviteLink: string }> {\n // TODO: Verify inviter has admin/owner role in org\n // TODO: Check if user is already a member\n\n const appUrl = process.env.APP_URL || 'http://localhost:3000';\n const inviteToken = generateInviteToken();\n const inviteLink = \\`\\${appUrl}/invite/\\${inviteToken}\\`;\n\n // TODO: Create pending invitation record in database\n // TODO: Send invitation email to data.email with inviteLink\n\n return { inviteLink };\n}\n\nexport async function acceptInvite(\n inviteToken: string,\n userId: string,\n): Promise<OrgMember | null> {\n // TODO: Look up invitation by token, verify it is not expired\n // TODO: Create membership record for the user\n // TODO: Mark invitation as accepted\n return null;\n}\n\nexport async function removeMember(\n orgId: string,\n memberId: string,\n removerId: string,\n): Promise<boolean> {\n // TODO: Verify remover has admin/owner role\n // TODO: Prevent removing the last owner\n // TODO: Delete membership record from database\n return false;\n}\n\nexport async function listMembers(orgId: string, userId: string): Promise<OrgMember[]> {\n // TODO: Verify user is a member of the org\n // TODO: Query all members for the org\n return [];\n}\n\nexport async function updateMemberRole(\n orgId: string,\n memberId: string,\n role: OrgRole,\n updaterId: string,\n): Promise<OrgMember | null> {\n // TODO: Verify updater is owner (only owners can change roles)\n // TODO: Prevent demoting the last owner\n // TODO: Update membership role in database\n return null;\n}\n`);\n\n // ── Routes ──\n await writeFile(path.join(orgDir, 'organizations.routes.ts'), `import { Router } from 'express';\nimport type { Request, Response } from 'express';\nimport {\n createOrganization,\n listOrganizations,\n getOrganization,\n updateOrganization,\n deleteOrganization,\n inviteMember,\n acceptInvite,\n removeMember,\n listMembers,\n updateMemberRole,\n} from './organizations.service.js';\n\n// TODO: Import your auth middleware\n// import { authMiddleware } from '../auth/auth.middleware.js';\n\nconst organizationsRouter = Router();\n\n// TODO: Uncomment to protect all routes\n// organizationsRouter.use(authMiddleware);\n\n// Create organization\norganizationsRouter.post('/', async (req: Request, res: Response) => {\n try {\n const userId = (req as any).user?.id || (req as any).user?.sub;\n const org = await createOrganization(req.body, userId);\n res.status(201).json(org);\n } catch (err: any) {\n res.status(400).json({ error: err.message });\n }\n});\n\n// List user's organizations\norganizationsRouter.get('/', async (req: Request, res: Response) => {\n try {\n const userId = (req as any).user?.id || (req as any).user?.sub;\n const orgs = await listOrganizations(userId);\n res.json(orgs);\n } catch (err: any) {\n res.status(500).json({ error: err.message });\n }\n});\n\n// Get single organization\norganizationsRouter.get('/:orgId', async (req: Request, res: Response) => {\n try {\n const userId = (req as any).user?.id || (req as any).user?.sub;\n const org = await getOrganization(req.params.orgId, userId);\n if (!org) return res.status(404).json({ error: 'Organization not found' });\n res.json(org);\n } catch (err: any) {\n res.status(500).json({ error: err.message });\n }\n});\n\n// Update organization\norganizationsRouter.put('/:orgId', async (req: Request, res: Response) => {\n try {\n const userId = (req as any).user?.id || (req as any).user?.sub;\n const org = await updateOrganization(req.params.orgId, req.body, userId);\n if (!org) return res.status(404).json({ error: 'Organization not found' });\n res.json(org);\n } catch (err: any) {\n res.status(400).json({ error: err.message });\n }\n});\n\n// Delete organization\norganizationsRouter.delete('/:orgId', async (req: Request, res: Response) => {\n try {\n const userId = (req as any).user?.id || (req as any).user?.sub;\n const deleted = await deleteOrganization(req.params.orgId, userId);\n if (!deleted) return res.status(404).json({ error: 'Organization not found' });\n res.status(204).send();\n } catch (err: any) {\n res.status(500).json({ error: err.message });\n }\n});\n\n// Invite member to organization\norganizationsRouter.post('/:orgId/invite', async (req: Request, res: Response) => {\n try {\n const userId = (req as any).user?.id || (req as any).user?.sub;\n const result = await inviteMember(req.params.orgId, req.body, userId);\n res.json(result);\n } catch (err: any) {\n res.status(400).json({ error: err.message });\n }\n});\n\n// Accept invitation\norganizationsRouter.post('/invite/:token/accept', async (req: Request, res: Response) => {\n try {\n const userId = (req as any).user?.id || (req as any).user?.sub;\n const member = await acceptInvite(req.params.token, userId);\n if (!member) return res.status(404).json({ error: 'Invalid or expired invite' });\n res.json(member);\n } catch (err: any) {\n res.status(400).json({ error: err.message });\n }\n});\n\n// List organization members\norganizationsRouter.get('/:orgId/members', async (req: Request, res: Response) => {\n try {\n const userId = (req as any).user?.id || (req as any).user?.sub;\n const members = await listMembers(req.params.orgId, userId);\n res.json(members);\n } catch (err: any) {\n res.status(500).json({ error: err.message });\n }\n});\n\n// Remove member from organization\norganizationsRouter.delete('/:orgId/members/:memberId', async (req: Request, res: Response) => {\n try {\n const userId = (req as any).user?.id || (req as any).user?.sub;\n const removed = await removeMember(req.params.orgId, req.params.memberId, userId);\n if (!removed) return res.status(404).json({ error: 'Member not found' });\n res.status(204).send();\n } catch (err: any) {\n res.status(500).json({ error: err.message });\n }\n});\n\n// Update member role\norganizationsRouter.put('/:orgId/members/:memberId/role', async (req: Request, res: Response) => {\n try {\n const userId = (req as any).user?.id || (req as any).user?.sub;\n const member = await updateMemberRole(\n req.params.orgId,\n req.params.memberId,\n req.body.role,\n userId,\n );\n if (!member) return res.status(404).json({ error: 'Member not found' });\n res.json(member);\n } catch (err: any) {\n res.status(400).json({ error: err.message });\n }\n});\n\nexport { organizationsRouter };\n`);\n\n // ──────────────────────────────────────────────\n // Fastify backend\n // ──────────────────────────────────────────────\n } else {\n // ── Service ──\n await writeFile(path.join(orgDir, 'organizations.service.ts'), `export type OrgRole = 'owner' | 'admin' | 'member';\n\nexport interface Organization {\n id: string;\n name: string;\n slug: string;\n description?: string;\n createdAt: Date;\n}\n\nexport interface OrgMember {\n id: string;\n userId: string;\n email: string;\n orgId: string;\n role: OrgRole;\n joinedAt: Date;\n}\n\nfunction generateSlug(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-|-$)/g, '');\n}\n\nfunction generateInviteToken(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n}\n\nexport async function createOrganization(\n data: { name: string; slug?: string; description?: string },\n ownerId: string,\n): Promise<Organization> {\n const slug = data.slug || generateSlug(data.name);\n\n // TODO: Persist organization to database\n const org: Organization = {\n id: 'org-' + Date.now(),\n name: data.name,\n slug,\n description: data.description,\n createdAt: new Date(),\n };\n\n // TODO: Create owner membership record\n // await addMemberToOrg(org.id, ownerId, ownerEmail, 'owner');\n\n return org;\n}\n\nexport async function listOrganizations(userId: string): Promise<Organization[]> {\n // TODO: Query organizations where user is a member\n return [];\n}\n\nexport async function getOrganization(orgId: string, userId: string): Promise<Organization | null> {\n // TODO: Query organization by ID and verify user membership\n return null;\n}\n\nexport async function updateOrganization(\n orgId: string,\n data: { name?: string; description?: string },\n userId: string,\n): Promise<Organization | null> {\n // TODO: Verify user has admin/owner role in org\n // TODO: Update organization in database\n return null;\n}\n\nexport async function deleteOrganization(orgId: string, userId: string): Promise<boolean> {\n // TODO: Verify user is owner of org\n // TODO: Delete organization and all memberships from database\n return false;\n}\n\nexport async function inviteMember(\n orgId: string,\n data: { email: string; role?: 'admin' | 'member' },\n inviterId: string,\n): Promise<{ inviteLink: string }> {\n // TODO: Verify inviter has admin/owner role in org\n // TODO: Check if user is already a member\n\n const appUrl = process.env.APP_URL || 'http://localhost:3000';\n const inviteToken = generateInviteToken();\n const inviteLink = \\`\\${appUrl}/invite/\\${inviteToken}\\`;\n\n // TODO: Create pending invitation record in database\n // TODO: Send invitation email to data.email with inviteLink\n\n return { inviteLink };\n}\n\nexport async function acceptInvite(\n inviteToken: string,\n userId: string,\n): Promise<OrgMember | null> {\n // TODO: Look up invitation by token, verify it is not expired\n // TODO: Create membership record for the user\n // TODO: Mark invitation as accepted\n return null;\n}\n\nexport async function removeMember(\n orgId: string,\n memberId: string,\n removerId: string,\n): Promise<boolean> {\n // TODO: Verify remover has admin/owner role\n // TODO: Prevent removing the last owner\n // TODO: Delete membership record from database\n return false;\n}\n\nexport async function listMembers(orgId: string, userId: string): Promise<OrgMember[]> {\n // TODO: Verify user is a member of the org\n // TODO: Query all members for the org\n return [];\n}\n\nexport async function updateMemberRole(\n orgId: string,\n memberId: string,\n role: OrgRole,\n updaterId: string,\n): Promise<OrgMember | null> {\n // TODO: Verify updater is owner (only owners can change roles)\n // TODO: Prevent demoting the last owner\n // TODO: Update membership role in database\n return null;\n}\n`);\n\n // ── Routes (Fastify plugin) ──\n await writeFile(path.join(orgDir, 'organizations.routes.ts'), `import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';\n\n// TODO: Import your auth hook\n// import { authHook } from '../auth/auth.hook.js';\n\nimport {\n createOrganization,\n listOrganizations,\n getOrganization,\n updateOrganization,\n deleteOrganization,\n inviteMember,\n acceptInvite,\n removeMember,\n listMembers,\n updateMemberRole,\n} from './organizations.service.js';\n\nexport async function organizationRoutes(app: FastifyInstance) {\n // TODO: Uncomment to protect all routes\n // app.addHook('onRequest', authHook);\n\n // Create organization\n app.post('/api/organizations', async (request: FastifyRequest, reply: FastifyReply) => {\n const userId = (request as any).user?.id || (request as any).user?.sub;\n const body = request.body as { name: string; slug?: string; description?: string };\n const org = await createOrganization(body, userId);\n return reply.status(201).send(org);\n });\n\n // List user's organizations\n app.get('/api/organizations', async (request: FastifyRequest) => {\n const userId = (request as any).user?.id || (request as any).user?.sub;\n return listOrganizations(userId);\n });\n\n // Get single organization\n app.get('/api/organizations/:orgId', async (request: FastifyRequest, reply: FastifyReply) => {\n const { orgId } = request.params as { orgId: string };\n const userId = (request as any).user?.id || (request as any).user?.sub;\n const org = await getOrganization(orgId, userId);\n if (!org) return reply.status(404).send({ error: 'Organization not found' });\n return org;\n });\n\n // Update organization\n app.put('/api/organizations/:orgId', async (request: FastifyRequest, reply: FastifyReply) => {\n const { orgId } = request.params as { orgId: string };\n const userId = (request as any).user?.id || (request as any).user?.sub;\n const body = request.body as { name?: string; description?: string };\n const org = await updateOrganization(orgId, body, userId);\n if (!org) return reply.status(404).send({ error: 'Organization not found' });\n return org;\n });\n\n // Delete organization\n app.delete('/api/organizations/:orgId', async (request: FastifyRequest, reply: FastifyReply) => {\n const { orgId } = request.params as { orgId: string };\n const userId = (request as any).user?.id || (request as any).user?.sub;\n const deleted = await deleteOrganization(orgId, userId);\n if (!deleted) return reply.status(404).send({ error: 'Organization not found' });\n return reply.status(204).send();\n });\n\n // Invite member to organization\n app.post('/api/organizations/:orgId/invite', async (request: FastifyRequest) => {\n const { orgId } = request.params as { orgId: string };\n const userId = (request as any).user?.id || (request as any).user?.sub;\n const body = request.body as { email: string; role?: 'admin' | 'member' };\n return inviteMember(orgId, body, userId);\n });\n\n // Accept invitation\n app.post('/api/organizations/invite/:token/accept', async (request: FastifyRequest, reply: FastifyReply) => {\n const { token } = request.params as { token: string };\n const userId = (request as any).user?.id || (request as any).user?.sub;\n const member = await acceptInvite(token, userId);\n if (!member) return reply.status(404).send({ error: 'Invalid or expired invite' });\n return member;\n });\n\n // List organization members\n app.get('/api/organizations/:orgId/members', async (request: FastifyRequest) => {\n const { orgId } = request.params as { orgId: string };\n const userId = (request as any).user?.id || (request as any).user?.sub;\n return listMembers(orgId, userId);\n });\n\n // Remove member from organization\n app.delete('/api/organizations/:orgId/members/:memberId', async (request: FastifyRequest, reply: FastifyReply) => {\n const { orgId, memberId } = request.params as { orgId: string; memberId: string };\n const userId = (request as any).user?.id || (request as any).user?.sub;\n const removed = await removeMember(orgId, memberId, userId);\n if (!removed) return reply.status(404).send({ error: 'Member not found' });\n return reply.status(204).send();\n });\n\n // Update member role\n app.put('/api/organizations/:orgId/members/:memberId/role', async (request: FastifyRequest, reply: FastifyReply) => {\n const { orgId, memberId } = request.params as { orgId: string; memberId: string };\n const userId = (request as any).user?.id || (request as any).user?.sub;\n const body = request.body as { role: 'owner' | 'admin' | 'member' };\n const member = await updateMemberRole(orgId, memberId, body.role, userId);\n if (!member) return reply.status(404).send({ error: 'Member not found' });\n return member;\n });\n}\n`);\n }\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\n// ---------------------------------------------------------------------------\n// Shared plans configuration (used by all backends)\n// ---------------------------------------------------------------------------\nconst PLANS_CONFIG = `/**\n * Stripe Billing Plans Configuration\n *\n * Replace the priceId placeholders with real Stripe Price IDs from your\n * dashboard (https://dashboard.stripe.com/products).\n *\n * Each plan maps to a Stripe Price object created in your Stripe account.\n */\n\nexport interface Plan {\n id: string;\n name: string;\n description: string;\n priceId: string;\n mode: 'subscription';\n interval: 'month' | 'year';\n features: string[];\n}\n\nexport const plans: Plan[] = [\n {\n id: 'free',\n name: 'Free',\n description: 'Get started with the essentials',\n priceId: process.env.STRIPE_PRICE_FREE || 'price_free_placeholder',\n mode: 'subscription',\n interval: 'month',\n features: [\n 'Up to 1 project',\n 'Basic analytics',\n 'Community support',\n '1 GB storage',\n ],\n },\n {\n id: 'pro',\n name: 'Pro',\n description: 'Everything you need to grow',\n priceId: process.env.STRIPE_PRICE_PRO || 'price_pro_placeholder',\n mode: 'subscription',\n interval: 'month',\n features: [\n 'Unlimited projects',\n 'Advanced analytics',\n 'Priority email support',\n '50 GB storage',\n 'Custom domains',\n 'Team collaboration (up to 5 members)',\n ],\n },\n {\n id: 'enterprise',\n name: 'Enterprise',\n description: 'Advanced features for scaling teams',\n priceId: process.env.STRIPE_PRICE_ENTERPRISE || 'price_enterprise_placeholder',\n mode: 'subscription',\n interval: 'month',\n features: [\n 'Unlimited projects',\n 'Real-time analytics',\n 'Dedicated account manager',\n 'Unlimited storage',\n 'Custom domains',\n 'Unlimited team members',\n 'SSO / SAML',\n 'SLA guarantee',\n 'Audit logs',\n ],\n },\n];\n\n/**\n * Find a plan by its identifier.\n */\nexport function getPlanById(id: string): Plan | undefined {\n return plans.find((p) => p.id === id);\n}\n\n/**\n * Find a plan by its Stripe Price ID.\n */\nexport function getPlanByPriceId(priceId: string): Plan | undefined {\n return plans.find((p) => p.priceId === priceId);\n}\n`;\n\n// ---------------------------------------------------------------------------\n// NestJS files\n// ---------------------------------------------------------------------------\n\nconst NESTJS_BILLING_SERVICE = `import { Injectable, Logger } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Stripe from 'stripe';\nimport { plans, getPlanByPriceId } from './plans.config';\n\n/**\n * Handles all Stripe Billing operations including customer management,\n * checkout sessions, customer portal, and webhook event processing.\n */\n@Injectable()\nexport class BillingService {\n private readonly stripe: Stripe;\n private readonly logger = new Logger(BillingService.name);\n private readonly webhookSecret: string;\n\n constructor(private readonly configService: ConfigService) {\n this.stripe = new Stripe(\n this.configService.getOrThrow<string>('STRIPE_SECRET_KEY'),\n { apiVersion: '2024-12-18.acacia' },\n );\n this.webhookSecret = this.configService.getOrThrow<string>('STRIPE_WEBHOOK_SECRET');\n }\n\n // -----------------------------------------------------------------------\n // Customer management\n // -----------------------------------------------------------------------\n\n /**\n * Create a Stripe customer and return the customer object.\n * Store \\`customer.id\\` in your database alongside the user record.\n */\n async createCustomer(params: {\n email: string;\n name?: string;\n metadata?: Record<string, string>;\n }): Promise<Stripe.Customer> {\n this.logger.log(\\`Creating Stripe customer for \\${params.email}\\`);\n return this.stripe.customers.create({\n email: params.email,\n name: params.name,\n metadata: params.metadata ?? {},\n });\n }\n\n /**\n * Retrieve a Stripe customer by ID.\n */\n async getCustomer(customerId: string): Promise<Stripe.Customer | Stripe.DeletedCustomer> {\n return this.stripe.customers.retrieve(customerId);\n }\n\n // -----------------------------------------------------------------------\n // Checkout\n // -----------------------------------------------------------------------\n\n /**\n * Create a Stripe Checkout Session in subscription mode.\n *\n * @returns The checkout session with a \\`url\\` to redirect the user to.\n */\n async createCheckoutSession(params: {\n customerId: string;\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n }): Promise<Stripe.Checkout.Session> {\n this.logger.log(\\`Creating checkout session for customer \\${params.customerId}\\`);\n return this.stripe.checkout.sessions.create({\n customer: params.customerId,\n mode: 'subscription',\n payment_method_types: ['card'],\n line_items: [{ price: params.priceId, quantity: 1 }],\n success_url: params.successUrl,\n cancel_url: params.cancelUrl,\n allow_promotion_codes: true,\n billing_address_collection: 'auto',\n subscription_data: {\n metadata: { priceId: params.priceId },\n },\n });\n }\n\n // -----------------------------------------------------------------------\n // Customer Portal\n // -----------------------------------------------------------------------\n\n /**\n * Create a Stripe Customer Portal session so the user can manage their\n * subscription (upgrade, downgrade, cancel, update payment method).\n */\n async createPortalSession(params: {\n customerId: string;\n returnUrl: string;\n }): Promise<Stripe.BillingPortal.Session> {\n this.logger.log(\\`Creating portal session for customer \\${params.customerId}\\`);\n return this.stripe.billingPortal.sessions.create({\n customer: params.customerId,\n return_url: params.returnUrl,\n });\n }\n\n // -----------------------------------------------------------------------\n // Subscription queries\n // -----------------------------------------------------------------------\n\n /**\n * Retrieve the active subscription for a customer.\n * Returns the first active/trialing subscription or null.\n */\n async getActiveSubscription(customerId: string): Promise<Stripe.Subscription | null> {\n const subscriptions = await this.stripe.subscriptions.list({\n customer: customerId,\n status: 'active',\n limit: 1,\n expand: ['data.default_payment_method'],\n });\n\n if (subscriptions.data.length === 0) {\n // Also check for trialing subscriptions\n const trialing = await this.stripe.subscriptions.list({\n customer: customerId,\n status: 'trialing',\n limit: 1,\n expand: ['data.default_payment_method'],\n });\n return trialing.data[0] ?? null;\n }\n\n return subscriptions.data[0] ?? null;\n }\n\n /**\n * Build a subscription status summary for the frontend.\n */\n async getSubscriptionStatus(customerId: string) {\n const subscription = await this.getActiveSubscription(customerId);\n\n if (!subscription) {\n return {\n active: false,\n plan: null,\n status: 'none' as const,\n currentPeriodEnd: null,\n cancelAtPeriodEnd: false,\n };\n }\n\n const priceId = subscription.items.data[0]?.price.id;\n const plan = priceId ? getPlanByPriceId(priceId) : null;\n\n return {\n active: ['active', 'trialing'].includes(subscription.status),\n plan: plan ?? null,\n status: subscription.status,\n currentPeriodEnd: new Date(subscription.current_period_end * 1000).toISOString(),\n cancelAtPeriodEnd: subscription.cancel_at_period_end,\n };\n }\n\n // -----------------------------------------------------------------------\n // Webhook handling\n // -----------------------------------------------------------------------\n\n /**\n * Verify and construct a Stripe webhook event from the raw request body.\n */\n constructWebhookEvent(rawBody: Buffer, signature: string): Stripe.Event {\n return this.stripe.webhooks.constructEvent(rawBody, signature, this.webhookSecret);\n }\n\n /**\n * Process a verified Stripe webhook event.\n *\n * This method handles the core subscription lifecycle events.\n * Extend with your own database logic where indicated by TODO comments.\n */\n async handleWebhookEvent(event: Stripe.Event): Promise<void> {\n switch (event.type) {\n case 'customer.subscription.created': {\n const subscription = event.data.object as Stripe.Subscription;\n this.logger.log(\n \\`Subscription created: \\${subscription.id} for customer \\${subscription.customer}\\`,\n );\n // TODO: Store subscription details in your database.\n // Example: await this.usersService.updateSubscription(subscription.customer, {\n // subscriptionId: subscription.id,\n // status: subscription.status,\n // priceId: subscription.items.data[0]?.price.id,\n // currentPeriodEnd: new Date(subscription.current_period_end * 1000),\n // });\n break;\n }\n\n case 'customer.subscription.updated': {\n const subscription = event.data.object as Stripe.Subscription;\n this.logger.log(\n \\`Subscription updated: \\${subscription.id} — status: \\${subscription.status}\\`,\n );\n // TODO: Update subscription details in your database.\n // Handle plan changes, trial-to-active transitions, cancellation scheduling, etc.\n break;\n }\n\n case 'customer.subscription.deleted': {\n const subscription = event.data.object as Stripe.Subscription;\n this.logger.log(\\`Subscription deleted: \\${subscription.id}\\`);\n // TODO: Mark the user's subscription as cancelled in your database.\n // Revoke premium access or downgrade to free tier.\n break;\n }\n\n case 'invoice.payment_succeeded': {\n const invoice = event.data.object as Stripe.Invoice;\n this.logger.log(\n \\`Payment succeeded for invoice \\${invoice.id} — amount: \\${invoice.amount_paid}\\`,\n );\n // TODO: Record successful payment. Update subscription period, send receipt email, etc.\n break;\n }\n\n case 'invoice.payment_failed': {\n const invoice = event.data.object as Stripe.Invoice;\n this.logger.warn(\n \\`Payment failed for invoice \\${invoice.id} — customer: \\${invoice.customer}\\`,\n );\n // TODO: Notify user about the failed payment.\n // Stripe will automatically retry based on your retry settings.\n // Consider sending a dunning email or showing an in-app warning.\n break;\n }\n\n default:\n this.logger.debug(\\`Unhandled webhook event type: \\${event.type}\\`);\n }\n }\n}\n`;\n\nconst NESTJS_BILLING_CONTROLLER = `import {\n Controller,\n Post,\n Get,\n Body,\n Req,\n Res,\n Headers,\n HttpCode,\n HttpStatus,\n BadRequestException,\n Logger,\n} from '@nestjs/common';\nimport type { Request, Response } from 'express';\nimport { BillingService } from './billing.service';\nimport { plans } from './plans.config';\n\n@Controller('billing')\nexport class BillingController {\n private readonly logger = new Logger(BillingController.name);\n\n constructor(private readonly billingService: BillingService) {}\n\n /**\n * GET /billing/plans\n * Returns available subscription plans.\n */\n @Get('plans')\n getPlans() {\n return { plans };\n }\n\n /**\n * POST /billing/create-checkout-session\n * Creates a Stripe Checkout Session and returns the URL.\n */\n @Post('create-checkout-session')\n async createCheckoutSession(\n @Body()\n body: {\n customerId: string;\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n },\n ) {\n if (!body.customerId || !body.priceId) {\n throw new BadRequestException('customerId and priceId are required');\n }\n\n const session = await this.billingService.createCheckoutSession({\n customerId: body.customerId,\n priceId: body.priceId,\n successUrl: body.successUrl,\n cancelUrl: body.cancelUrl,\n });\n\n return { sessionId: session.id, url: session.url };\n }\n\n /**\n * POST /billing/create-portal-session\n * Creates a Stripe Customer Portal session and returns the URL.\n */\n @Post('create-portal-session')\n async createPortalSession(\n @Body() body: { customerId: string; returnUrl: string },\n ) {\n if (!body.customerId) {\n throw new BadRequestException('customerId is required');\n }\n\n const session = await this.billingService.createPortalSession({\n customerId: body.customerId,\n returnUrl: body.returnUrl,\n });\n\n return { url: session.url };\n }\n\n /**\n * GET /billing/subscription-status?customerId=cus_xxx\n * Returns the current subscription status for a customer.\n */\n @Get('subscription-status')\n async getSubscriptionStatus(@Req() req: Request) {\n const customerId = req.query.customerId as string;\n if (!customerId) {\n throw new BadRequestException('customerId query parameter is required');\n }\n\n return this.billingService.getSubscriptionStatus(customerId);\n }\n\n /**\n * POST /billing/webhook\n * Stripe webhook endpoint. Must receive the raw body for signature verification.\n *\n * IMPORTANT: This endpoint must be excluded from any body-parsing middleware.\n * In your main.ts, configure raw body parsing:\n *\n * const app = await NestFactory.create(AppModule, { rawBody: true });\n */\n @Post('webhook')\n @HttpCode(HttpStatus.OK)\n async handleWebhook(\n @Req() req: Request,\n @Headers('stripe-signature') signature: string,\n @Res() res: Response,\n ) {\n if (!signature) {\n throw new BadRequestException('Missing stripe-signature header');\n }\n\n let event;\n try {\n // req.body should be a Buffer when rawBody is enabled in NestFactory\n const rawBody = (req as any).rawBody as Buffer;\n if (!rawBody) {\n throw new Error(\n 'Raw body not available. Enable rawBody in NestFactory.create options.',\n );\n }\n event = this.billingService.constructWebhookEvent(rawBody, signature);\n } catch (err: any) {\n this.logger.error(\\`Webhook signature verification failed: \\${err.message}\\`);\n return res.status(HttpStatus.BAD_REQUEST).json({\n error: \\`Webhook Error: \\${err.message}\\`,\n });\n }\n\n await this.billingService.handleWebhookEvent(event);\n\n return res.json({ received: true });\n }\n}\n`;\n\nconst NESTJS_BILLING_MODULE = `import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { BillingService } from './billing.service';\nimport { BillingController } from './billing.controller';\n\n@Module({\n imports: [ConfigModule],\n controllers: [BillingController],\n providers: [BillingService],\n exports: [BillingService],\n})\nexport class BillingModule {}\n`;\n\n// ---------------------------------------------------------------------------\n// Express files\n// ---------------------------------------------------------------------------\n\nconst EXPRESS_BILLING_SERVICE = `import Stripe from 'stripe';\n\n/**\n * Stripe Billing Service — Express / standalone edition.\n *\n * Centralises all Stripe API interactions for subscription billing.\n */\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY || '', {\n apiVersion: '2024-12-18.acacia',\n});\n\nconst webhookSecret = process.env.STRIPE_WEBHOOK_SECRET || '';\n\n// ---------------------------------------------------------------------------\n// Customer management\n// ---------------------------------------------------------------------------\n\n/**\n * Create a Stripe customer. Store \\`customer.id\\` in your database.\n */\nexport async function createCustomer(params: {\n email: string;\n name?: string;\n metadata?: Record<string, string>;\n}): Promise<Stripe.Customer> {\n return stripe.customers.create({\n email: params.email,\n name: params.name,\n metadata: params.metadata ?? {},\n });\n}\n\n/**\n * Retrieve a Stripe customer by ID.\n */\nexport async function getCustomer(\n customerId: string,\n): Promise<Stripe.Customer | Stripe.DeletedCustomer> {\n return stripe.customers.retrieve(customerId);\n}\n\n// ---------------------------------------------------------------------------\n// Checkout\n// ---------------------------------------------------------------------------\n\n/**\n * Create a Stripe Checkout Session in subscription mode.\n */\nexport async function createCheckoutSession(params: {\n customerId: string;\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n}): Promise<Stripe.Checkout.Session> {\n return stripe.checkout.sessions.create({\n customer: params.customerId,\n mode: 'subscription',\n payment_method_types: ['card'],\n line_items: [{ price: params.priceId, quantity: 1 }],\n success_url: params.successUrl,\n cancel_url: params.cancelUrl,\n allow_promotion_codes: true,\n billing_address_collection: 'auto',\n subscription_data: {\n metadata: { priceId: params.priceId },\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// Customer Portal\n// ---------------------------------------------------------------------------\n\n/**\n * Create a Stripe Customer Portal session.\n */\nexport async function createPortalSession(params: {\n customerId: string;\n returnUrl: string;\n}): Promise<Stripe.BillingPortal.Session> {\n return stripe.billingPortal.sessions.create({\n customer: params.customerId,\n return_url: params.returnUrl,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Subscription queries\n// ---------------------------------------------------------------------------\n\nimport { getPlanByPriceId } from './plans.config.js';\n\n/**\n * Get the active (or trialing) subscription for a customer, or null.\n */\nexport async function getActiveSubscription(\n customerId: string,\n): Promise<Stripe.Subscription | null> {\n const subscriptions = await stripe.subscriptions.list({\n customer: customerId,\n status: 'active',\n limit: 1,\n expand: ['data.default_payment_method'],\n });\n\n if (subscriptions.data.length === 0) {\n const trialing = await stripe.subscriptions.list({\n customer: customerId,\n status: 'trialing',\n limit: 1,\n expand: ['data.default_payment_method'],\n });\n return trialing.data[0] ?? null;\n }\n\n return subscriptions.data[0] ?? null;\n}\n\n/**\n * Build a subscription status summary for the frontend.\n */\nexport async function getSubscriptionStatus(customerId: string) {\n const subscription = await getActiveSubscription(customerId);\n\n if (!subscription) {\n return {\n active: false,\n plan: null,\n status: 'none' as const,\n currentPeriodEnd: null,\n cancelAtPeriodEnd: false,\n };\n }\n\n const priceId = subscription.items.data[0]?.price.id;\n const plan = priceId ? getPlanByPriceId(priceId) : null;\n\n return {\n active: ['active', 'trialing'].includes(subscription.status),\n plan: plan ?? null,\n status: subscription.status,\n currentPeriodEnd: new Date(subscription.current_period_end * 1000).toISOString(),\n cancelAtPeriodEnd: subscription.cancel_at_period_end,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Webhook\n// ---------------------------------------------------------------------------\n\n/**\n * Verify and construct a webhook event from the raw body.\n */\nexport function constructWebhookEvent(\n rawBody: Buffer,\n signature: string,\n): Stripe.Event {\n return stripe.webhooks.constructEvent(rawBody, signature, webhookSecret);\n}\n\n/**\n * Process a verified Stripe webhook event.\n *\n * Handles the core subscription lifecycle. Extend with your own logic.\n */\nexport async function handleWebhookEvent(event: Stripe.Event): Promise<void> {\n switch (event.type) {\n case 'customer.subscription.created': {\n const subscription = event.data.object as Stripe.Subscription;\n console.log(\n \\`[Billing] Subscription created: \\${subscription.id} for customer \\${subscription.customer}\\`,\n );\n // TODO: Store subscription details in your database.\n break;\n }\n\n case 'customer.subscription.updated': {\n const subscription = event.data.object as Stripe.Subscription;\n console.log(\n \\`[Billing] Subscription updated: \\${subscription.id} — status: \\${subscription.status}\\`,\n );\n // TODO: Update subscription in your database (plan changes, cancellations, etc.).\n break;\n }\n\n case 'customer.subscription.deleted': {\n const subscription = event.data.object as Stripe.Subscription;\n console.log(\\`[Billing] Subscription deleted: \\${subscription.id}\\`);\n // TODO: Revoke premium access or downgrade to free tier.\n break;\n }\n\n case 'invoice.payment_succeeded': {\n const invoice = event.data.object as Stripe.Invoice;\n console.log(\n \\`[Billing] Payment succeeded: invoice \\${invoice.id} — amount \\${invoice.amount_paid}\\`,\n );\n // TODO: Record payment, update subscription period, send receipt email.\n break;\n }\n\n case 'invoice.payment_failed': {\n const invoice = event.data.object as Stripe.Invoice;\n console.warn(\n \\`[Billing] Payment failed: invoice \\${invoice.id} — customer \\${invoice.customer}\\`,\n );\n // TODO: Notify user about the failed payment, trigger dunning flow.\n break;\n }\n\n default:\n console.log(\\`[Billing] Unhandled event type: \\${event.type}\\`);\n }\n}\n`;\n\nconst EXPRESS_BILLING_ROUTES = `import { Router } from 'express';\nimport express from 'express';\nimport {\n createCheckoutSession,\n createPortalSession,\n getSubscriptionStatus,\n constructWebhookEvent,\n handleWebhookEvent,\n} from './billing.service.js';\nimport { plans } from './plans.config.js';\n\nconst billingRouter = Router();\n\n/**\n * GET /billing/plans\n * Returns available subscription plans.\n */\nbillingRouter.get('/plans', (_req, res) => {\n res.json({ plans });\n});\n\n/**\n * POST /billing/create-checkout-session\n * Creates a Stripe Checkout Session and returns the URL.\n */\nbillingRouter.post('/create-checkout-session', async (req, res) => {\n try {\n const { customerId, priceId, successUrl, cancelUrl } = req.body;\n\n if (!customerId || !priceId) {\n return res.status(400).json({ error: 'customerId and priceId are required' });\n }\n\n const session = await createCheckoutSession({\n customerId,\n priceId,\n successUrl,\n cancelUrl,\n });\n\n res.json({ sessionId: session.id, url: session.url });\n } catch (err: any) {\n console.error('[Billing] Checkout session error:', err.message);\n res.status(500).json({ error: 'Failed to create checkout session' });\n }\n});\n\n/**\n * POST /billing/create-portal-session\n * Creates a Stripe Customer Portal session and returns the URL.\n */\nbillingRouter.post('/create-portal-session', async (req, res) => {\n try {\n const { customerId, returnUrl } = req.body;\n\n if (!customerId) {\n return res.status(400).json({ error: 'customerId is required' });\n }\n\n const session = await createPortalSession({\n customerId,\n returnUrl,\n });\n\n res.json({ url: session.url });\n } catch (err: any) {\n console.error('[Billing] Portal session error:', err.message);\n res.status(500).json({ error: 'Failed to create portal session' });\n }\n});\n\n/**\n * GET /billing/subscription-status?customerId=cus_xxx\n * Returns the current subscription status for a customer.\n */\nbillingRouter.get('/subscription-status', async (req, res) => {\n try {\n const customerId = req.query.customerId as string;\n\n if (!customerId) {\n return res.status(400).json({ error: 'customerId query parameter is required' });\n }\n\n const status = await getSubscriptionStatus(customerId);\n res.json(status);\n } catch (err: any) {\n console.error('[Billing] Subscription status error:', err.message);\n res.status(500).json({ error: 'Failed to get subscription status' });\n }\n});\n\n/**\n * POST /billing/webhook\n * Stripe webhook endpoint.\n *\n * IMPORTANT: This route uses express.raw() to receive the raw body as a\n * Buffer, which is required for Stripe signature verification.\n * Do NOT apply JSON body parsing middleware to this route.\n */\nbillingRouter.post(\n '/webhook',\n express.raw({ type: 'application/json' }),\n async (req, res) => {\n const signature = req.headers['stripe-signature'] as string;\n\n if (!signature) {\n return res.status(400).json({ error: 'Missing stripe-signature header' });\n }\n\n let event;\n try {\n event = constructWebhookEvent(req.body, signature);\n } catch (err: any) {\n console.error(\\`[Billing] Webhook signature verification failed: \\${err.message}\\`);\n return res.status(400).json({ error: \\`Webhook Error: \\${err.message}\\` });\n }\n\n try {\n await handleWebhookEvent(event);\n } catch (err: any) {\n console.error(\\`[Billing] Webhook handler error: \\${err.message}\\`);\n return res.status(500).json({ error: 'Webhook handler failed' });\n }\n\n res.json({ received: true });\n },\n);\n\nexport { billingRouter };\n`;\n\n// ---------------------------------------------------------------------------\n// Fastify files\n// ---------------------------------------------------------------------------\n\nconst FASTIFY_BILLING_SERVICE = `import Stripe from 'stripe';\n\n/**\n * Stripe Billing Service — Fastify / standalone edition.\n *\n * Centralises all Stripe API interactions for subscription billing.\n */\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY || '', {\n apiVersion: '2024-12-18.acacia',\n});\n\nconst webhookSecret = process.env.STRIPE_WEBHOOK_SECRET || '';\n\n// ---------------------------------------------------------------------------\n// Customer management\n// ---------------------------------------------------------------------------\n\n/**\n * Create a Stripe customer. Store \\`customer.id\\` in your database.\n */\nexport async function createCustomer(params: {\n email: string;\n name?: string;\n metadata?: Record<string, string>;\n}): Promise<Stripe.Customer> {\n return stripe.customers.create({\n email: params.email,\n name: params.name,\n metadata: params.metadata ?? {},\n });\n}\n\n/**\n * Retrieve a Stripe customer by ID.\n */\nexport async function getCustomer(\n customerId: string,\n): Promise<Stripe.Customer | Stripe.DeletedCustomer> {\n return stripe.customers.retrieve(customerId);\n}\n\n// ---------------------------------------------------------------------------\n// Checkout\n// ---------------------------------------------------------------------------\n\n/**\n * Create a Stripe Checkout Session in subscription mode.\n */\nexport async function createCheckoutSession(params: {\n customerId: string;\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n}): Promise<Stripe.Checkout.Session> {\n return stripe.checkout.sessions.create({\n customer: params.customerId,\n mode: 'subscription',\n payment_method_types: ['card'],\n line_items: [{ price: params.priceId, quantity: 1 }],\n success_url: params.successUrl,\n cancel_url: params.cancelUrl,\n allow_promotion_codes: true,\n billing_address_collection: 'auto',\n subscription_data: {\n metadata: { priceId: params.priceId },\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// Customer Portal\n// ---------------------------------------------------------------------------\n\n/**\n * Create a Stripe Customer Portal session.\n */\nexport async function createPortalSession(params: {\n customerId: string;\n returnUrl: string;\n}): Promise<Stripe.BillingPortal.Session> {\n return stripe.billingPortal.sessions.create({\n customer: params.customerId,\n return_url: params.returnUrl,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Subscription queries\n// ---------------------------------------------------------------------------\n\nimport { getPlanByPriceId } from './plans.config.js';\n\n/**\n * Get the active (or trialing) subscription for a customer, or null.\n */\nexport async function getActiveSubscription(\n customerId: string,\n): Promise<Stripe.Subscription | null> {\n const subscriptions = await stripe.subscriptions.list({\n customer: customerId,\n status: 'active',\n limit: 1,\n expand: ['data.default_payment_method'],\n });\n\n if (subscriptions.data.length === 0) {\n const trialing = await stripe.subscriptions.list({\n customer: customerId,\n status: 'trialing',\n limit: 1,\n expand: ['data.default_payment_method'],\n });\n return trialing.data[0] ?? null;\n }\n\n return subscriptions.data[0] ?? null;\n}\n\n/**\n * Build a subscription status summary for the frontend.\n */\nexport async function getSubscriptionStatus(customerId: string) {\n const subscription = await getActiveSubscription(customerId);\n\n if (!subscription) {\n return {\n active: false,\n plan: null,\n status: 'none' as const,\n currentPeriodEnd: null,\n cancelAtPeriodEnd: false,\n };\n }\n\n const priceId = subscription.items.data[0]?.price.id;\n const plan = priceId ? getPlanByPriceId(priceId) : null;\n\n return {\n active: ['active', 'trialing'].includes(subscription.status),\n plan: plan ?? null,\n status: subscription.status,\n currentPeriodEnd: new Date(subscription.current_period_end * 1000).toISOString(),\n cancelAtPeriodEnd: subscription.cancel_at_period_end,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Webhook\n// ---------------------------------------------------------------------------\n\n/**\n * Verify and construct a webhook event from the raw body.\n */\nexport function constructWebhookEvent(\n rawBody: Buffer,\n signature: string,\n): Stripe.Event {\n return stripe.webhooks.constructEvent(rawBody, signature, webhookSecret);\n}\n\n/**\n * Process a verified Stripe webhook event.\n */\nexport async function handleWebhookEvent(event: Stripe.Event): Promise<void> {\n switch (event.type) {\n case 'customer.subscription.created': {\n const subscription = event.data.object as Stripe.Subscription;\n console.log(\n \\`[Billing] Subscription created: \\${subscription.id} for customer \\${subscription.customer}\\`,\n );\n // TODO: Store subscription details in your database.\n break;\n }\n\n case 'customer.subscription.updated': {\n const subscription = event.data.object as Stripe.Subscription;\n console.log(\n \\`[Billing] Subscription updated: \\${subscription.id} — status: \\${subscription.status}\\`,\n );\n // TODO: Update subscription in your database.\n break;\n }\n\n case 'customer.subscription.deleted': {\n const subscription = event.data.object as Stripe.Subscription;\n console.log(\\`[Billing] Subscription deleted: \\${subscription.id}\\`);\n // TODO: Revoke premium access or downgrade to free tier.\n break;\n }\n\n case 'invoice.payment_succeeded': {\n const invoice = event.data.object as Stripe.Invoice;\n console.log(\n \\`[Billing] Payment succeeded: invoice \\${invoice.id} — amount \\${invoice.amount_paid}\\`,\n );\n // TODO: Record payment, update subscription period.\n break;\n }\n\n case 'invoice.payment_failed': {\n const invoice = event.data.object as Stripe.Invoice;\n console.warn(\n \\`[Billing] Payment failed: invoice \\${invoice.id} — customer \\${invoice.customer}\\`,\n );\n // TODO: Notify user, trigger dunning flow.\n break;\n }\n\n default:\n console.log(\\`[Billing] Unhandled event type: \\${event.type}\\`);\n }\n}\n`;\n\nconst FASTIFY_BILLING_ROUTES = `import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';\nimport {\n createCheckoutSession,\n createPortalSession,\n getSubscriptionStatus,\n constructWebhookEvent,\n handleWebhookEvent,\n} from './billing.service.js';\nimport { plans } from './plans.config.js';\n\n/**\n * Fastify Billing Routes Plugin\n *\n * Register this plugin in your Fastify app:\n * app.register(billingRoutes, { prefix: '/api/billing' });\n */\nexport async function billingRoutes(app: FastifyInstance) {\n /**\n * GET /plans\n */\n app.get('/plans', async () => {\n return { plans };\n });\n\n /**\n * POST /create-checkout-session\n */\n app.post('/create-checkout-session', async (request: FastifyRequest, reply: FastifyReply) => {\n const { customerId, priceId, successUrl, cancelUrl } = request.body as {\n customerId: string;\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n };\n\n if (!customerId || !priceId) {\n return reply.status(400).send({ error: 'customerId and priceId are required' });\n }\n\n try {\n const session = await createCheckoutSession({\n customerId,\n priceId,\n successUrl,\n cancelUrl,\n });\n\n return { sessionId: session.id, url: session.url };\n } catch (err: any) {\n request.log.error(\\`Checkout session error: \\${err.message}\\`);\n return reply.status(500).send({ error: 'Failed to create checkout session' });\n }\n });\n\n /**\n * POST /create-portal-session\n */\n app.post('/create-portal-session', async (request: FastifyRequest, reply: FastifyReply) => {\n const { customerId, returnUrl } = request.body as {\n customerId: string;\n returnUrl: string;\n };\n\n if (!customerId) {\n return reply.status(400).send({ error: 'customerId is required' });\n }\n\n try {\n const session = await createPortalSession({\n customerId,\n returnUrl,\n });\n\n return { url: session.url };\n } catch (err: any) {\n request.log.error(\\`Portal session error: \\${err.message}\\`);\n return reply.status(500).send({ error: 'Failed to create portal session' });\n }\n });\n\n /**\n * GET /subscription-status?customerId=cus_xxx\n */\n app.get('/subscription-status', async (request: FastifyRequest, reply: FastifyReply) => {\n const { customerId } = request.query as { customerId: string };\n\n if (!customerId) {\n return reply.status(400).send({ error: 'customerId query parameter is required' });\n }\n\n try {\n const status = await getSubscriptionStatus(customerId);\n return status;\n } catch (err: any) {\n request.log.error(\\`Subscription status error: \\${err.message}\\`);\n return reply.status(500).send({ error: 'Failed to get subscription status' });\n }\n });\n\n /**\n * POST /webhook\n *\n * Stripe webhook endpoint. Requires the raw body for signature verification.\n *\n * Fastify config:\n * - addContentTypeParser for 'application/json' on this route returns raw Buffer.\n * - We use route-level config to achieve this.\n */\n app.post(\n '/webhook',\n {\n config: {\n rawBody: true,\n },\n },\n async (request: FastifyRequest, reply: FastifyReply) => {\n const signature = request.headers['stripe-signature'] as string;\n\n if (!signature) {\n return reply.status(400).send({ error: 'Missing stripe-signature header' });\n }\n\n let event;\n try {\n // Access the raw body — requires fastify-raw-body plugin or custom content type parser.\n // If using @fastify/raw-body, the raw buffer is available at request.rawBody.\n // If you registered a custom content type parser, request.body is already a Buffer.\n const rawBody = (request as any).rawBody ?? request.body;\n const bodyBuffer = Buffer.isBuffer(rawBody)\n ? rawBody\n : Buffer.from(typeof rawBody === 'string' ? rawBody : JSON.stringify(rawBody));\n\n event = constructWebhookEvent(bodyBuffer, signature);\n } catch (err: any) {\n request.log.error(\\`Webhook signature verification failed: \\${err.message}\\`);\n return reply.status(400).send({ error: \\`Webhook Error: \\${err.message}\\` });\n }\n\n try {\n await handleWebhookEvent(event);\n } catch (err: any) {\n request.log.error(\\`Webhook handler error: \\${err.message}\\`);\n return reply.status(500).send({ error: 'Webhook handler failed' });\n }\n\n return { received: true };\n },\n );\n}\n`;\n\n// ===========================================================================\n// Installer\n// ===========================================================================\n\nexport const stripeBillingInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n const billingDir = path.join(apiDir, 'src', 'billing');\n await ensureDir(billingDir);\n\n // -----------------------------------------------------------------------\n // Environment variables\n // -----------------------------------------------------------------------\n envEntries.push(\n {\n key: 'STRIPE_SECRET_KEY',\n value: '',\n category: 'Stripe Billing',\n comment: 'Get from https://dashboard.stripe.com/apikeys',\n },\n {\n key: 'STRIPE_WEBHOOK_SECRET',\n value: '',\n category: 'Stripe Billing',\n comment: 'Get from Stripe webhook endpoint settings (whsec_...)',\n },\n {\n key: 'STRIPE_PRICE_FREE',\n value: '',\n category: 'Stripe Billing',\n comment: 'Stripe Price ID for the Free plan',\n },\n {\n key: 'STRIPE_PRICE_PRO',\n value: '',\n category: 'Stripe Billing',\n comment: 'Stripe Price ID for the Pro plan',\n },\n {\n key: 'STRIPE_PRICE_ENTERPRISE',\n value: '',\n category: 'Stripe Billing',\n comment: 'Stripe Price ID for the Enterprise plan',\n },\n );\n\n // -----------------------------------------------------------------------\n // Plans configuration (shared across all backends)\n // -----------------------------------------------------------------------\n await writeFile(path.join(billingDir, 'plans.config.ts'), PLANS_CONFIG);\n\n // -----------------------------------------------------------------------\n // Backend-specific files\n // -----------------------------------------------------------------------\n if (config.backend === 'nestjs') {\n await writeFile(path.join(billingDir, 'billing.module.ts'), NESTJS_BILLING_MODULE);\n await writeFile(path.join(billingDir, 'billing.service.ts'), NESTJS_BILLING_SERVICE);\n await writeFile(path.join(billingDir, 'billing.controller.ts'), NESTJS_BILLING_CONTROLLER);\n } else if (config.backend === 'express') {\n await writeFile(path.join(billingDir, 'billing.service.ts'), EXPRESS_BILLING_SERVICE);\n await writeFile(path.join(billingDir, 'billing.routes.ts'), EXPRESS_BILLING_ROUTES);\n } else {\n // Fastify\n await writeFile(path.join(billingDir, 'billing.service.ts'), FASTIFY_BILLING_SERVICE);\n await writeFile(path.join(billingDir, 'billing.routes.ts'), FASTIFY_BILLING_ROUTES);\n }\n\n // -----------------------------------------------------------------------\n // Dependencies\n // -----------------------------------------------------------------------\n dependencies['stripe'] = deps.stripe;\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const websocketsInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'websockets'));\n\n envEntries.push(\n { key: 'WEBSOCKET_CORS_ORIGIN', value: 'http://localhost:3000', category: 'WebSockets', comment: 'Allowed CORS origin for WebSocket connections' },\n );\n\n if (config.backend === 'nestjs') {\n // ── NestJS Gateway ──────────────────────────────────────────────\n await writeFile(path.join(apiDir, 'src', 'websockets', 'events.gateway.ts'), `import {\n WebSocketGateway,\n WebSocketServer,\n SubscribeMessage,\n OnGatewayInit,\n OnGatewayConnection,\n OnGatewayDisconnect,\n MessageBody,\n ConnectedSocket,\n} from '@nestjs/websockets';\nimport { Logger } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { Server, Socket } from 'socket.io';\n\n@WebSocketGateway({\n cors: {\n origin: process.env.WEBSOCKET_CORS_ORIGIN || 'http://localhost:3000',\n credentials: true,\n },\n})\nexport class EventsGateway\n implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect\n{\n @WebSocketServer()\n server!: Server;\n\n private readonly logger = new Logger(EventsGateway.name);\n\n constructor(private readonly configService: ConfigService) {}\n\n afterInit() {\n this.logger.log('WebSocket Gateway initialized');\n }\n\n handleConnection(client: Socket) {\n this.logger.log(\\`Client connected: \\${client.id}\\`);\n }\n\n handleDisconnect(client: Socket) {\n this.logger.log(\\`Client disconnected: \\${client.id}\\`);\n }\n\n // ── Real-time messaging ──────────────────────────────────────────\n\n @SubscribeMessage('message')\n handleMessage(\n @ConnectedSocket() client: Socket,\n @MessageBody() payload: { room?: string; content: string },\n ) {\n this.logger.debug(\\`Message from \\${client.id}: \\${payload.content}\\`);\n\n if (payload.room) {\n client.to(payload.room).emit('message', {\n senderId: client.id,\n content: payload.content,\n timestamp: new Date().toISOString(),\n });\n } else {\n client.broadcast.emit('message', {\n senderId: client.id,\n content: payload.content,\n timestamp: new Date().toISOString(),\n });\n }\n\n return { status: 'ok' };\n }\n\n // ── Notifications ────────────────────────────────────────────────\n\n @SubscribeMessage('notification')\n handleNotification(\n @ConnectedSocket() client: Socket,\n @MessageBody() payload: { targetUserId?: string; title: string; body: string },\n ) {\n const notification = {\n title: payload.title,\n body: payload.body,\n timestamp: new Date().toISOString(),\n };\n\n if (payload.targetUserId) {\n this.server.to(\\`user:\\${payload.targetUserId}\\`).emit('notification', notification);\n } else {\n this.server.emit('notification', notification);\n }\n\n return { status: 'ok' };\n }\n\n // ── Room management ──────────────────────────────────────────────\n\n @SubscribeMessage('joinRoom')\n handleJoinRoom(\n @ConnectedSocket() client: Socket,\n @MessageBody() payload: { room: string },\n ) {\n client.join(payload.room);\n this.logger.log(\\`Client \\${client.id} joined room \\${payload.room}\\`);\n client.to(payload.room).emit('roomEvent', {\n type: 'joined',\n clientId: client.id,\n room: payload.room,\n });\n return { status: 'ok', room: payload.room };\n }\n\n @SubscribeMessage('leaveRoom')\n handleLeaveRoom(\n @ConnectedSocket() client: Socket,\n @MessageBody() payload: { room: string },\n ) {\n client.leave(payload.room);\n this.logger.log(\\`Client \\${client.id} left room \\${payload.room}\\`);\n client.to(payload.room).emit('roomEvent', {\n type: 'left',\n clientId: client.id,\n room: payload.room,\n });\n return { status: 'ok', room: payload.room };\n }\n\n // ── Utility: send to specific user or room from anywhere ────────\n\n sendToUser(userId: string, event: string, data: unknown) {\n this.server.to(\\`user:\\${userId}\\`).emit(event, data);\n }\n\n sendToRoom(room: string, event: string, data: unknown) {\n this.server.to(room).emit(event, data);\n }\n\n broadcast(event: string, data: unknown) {\n this.server.emit(event, data);\n }\n}\n`);\n\n // ── NestJS Module ───────────────────────────────────────────────\n await writeFile(path.join(apiDir, 'src', 'websockets', 'events.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { EventsGateway } from './events.gateway';\n\n@Global()\n@Module({\n providers: [EventsGateway],\n exports: [EventsGateway],\n})\nexport class EventsModule {}\n`);\n\n dependencies['@nestjs/websockets'] = deps['@nestjs/websockets'];\n dependencies['@nestjs/platform-socket.io'] = deps['@nestjs/platform-socket.io'];\n } else if (config.backend === 'express') {\n // ── Express + Socket.IO ─────────────────────────────────────────\n await writeFile(path.join(apiDir, 'src', 'websockets', 'socket.ts'), `import { Server as HttpServer } from 'http';\nimport { Server, Socket } from 'socket.io';\n\nlet io: Server;\n\n/**\n * Initialize Socket.IO and attach it to the existing HTTP server.\n * Call this once after creating your Express http.createServer().\n *\n * Example:\n * import http from 'http';\n * import express from 'express';\n * import { initSocket } from './websockets/socket.js';\n *\n * const app = express();\n * const server = http.createServer(app);\n * initSocket(server);\n * server.listen(3001);\n */\nexport function initSocket(server: HttpServer): Server {\n io = new Server(server, {\n cors: {\n origin: process.env.WEBSOCKET_CORS_ORIGIN || 'http://localhost:3000',\n credentials: true,\n },\n });\n\n io.on('connection', (socket: Socket) => {\n console.log(\\`Client connected: \\${socket.id}\\`);\n\n // ── Real-time messaging ────────────────────────────────────────\n socket.on('message', (payload: { room?: string; content: string }) => {\n const message = {\n senderId: socket.id,\n content: payload.content,\n timestamp: new Date().toISOString(),\n };\n\n if (payload.room) {\n socket.to(payload.room).emit('message', message);\n } else {\n socket.broadcast.emit('message', message);\n }\n });\n\n // ── Notifications ──────────────────────────────────────────────\n socket.on('notification', (payload: { targetUserId?: string; title: string; body: string }) => {\n const notification = {\n title: payload.title,\n body: payload.body,\n timestamp: new Date().toISOString(),\n };\n\n if (payload.targetUserId) {\n io.to(\\`user:\\${payload.targetUserId}\\`).emit('notification', notification);\n } else {\n io.emit('notification', notification);\n }\n });\n\n // ── Room management ────────────────────────────────────────────\n socket.on('joinRoom', (payload: { room: string }) => {\n socket.join(payload.room);\n console.log(\\`Client \\${socket.id} joined room \\${payload.room}\\`);\n socket.to(payload.room).emit('roomEvent', {\n type: 'joined',\n clientId: socket.id,\n room: payload.room,\n });\n });\n\n socket.on('leaveRoom', (payload: { room: string }) => {\n socket.leave(payload.room);\n console.log(\\`Client \\${socket.id} left room \\${payload.room}\\`);\n socket.to(payload.room).emit('roomEvent', {\n type: 'left',\n clientId: socket.id,\n room: payload.room,\n });\n });\n\n // ── Disconnect ─────────────────────────────────────────────────\n socket.on('disconnect', (reason: string) => {\n console.log(\\`Client disconnected: \\${socket.id} (\\${reason})\\`);\n });\n });\n\n return io;\n}\n\n/** Get the Socket.IO instance (available after initSocket) */\nexport function getIO(): Server {\n if (!io) {\n throw new Error('Socket.IO has not been initialized. Call initSocket(server) first.');\n }\n return io;\n}\n\n/** Send an event to a specific user room */\nexport function sendToUser(userId: string, event: string, data: unknown) {\n getIO().to(\\`user:\\${userId}\\`).emit(event, data);\n}\n\n/** Send an event to a specific room */\nexport function sendToRoom(room: string, event: string, data: unknown) {\n getIO().to(room).emit(event, data);\n}\n\n/** Broadcast an event to all connected clients */\nexport function broadcast(event: string, data: unknown) {\n getIO().emit(event, data);\n}\n`);\n } else {\n // ── Fastify + Socket.IO ─────────────────────────────────────────\n await writeFile(path.join(apiDir, 'src', 'websockets', 'socket.ts'), `import { FastifyInstance } from 'fastify';\nimport { Server, Socket } from 'socket.io';\n\nlet io: Server;\n\n/**\n * Initialize Socket.IO and attach it to the Fastify server instance.\n * Call this once after creating your Fastify server.\n *\n * Example:\n * import Fastify from 'fastify';\n * import { initSocket } from './websockets/socket.js';\n *\n * const server = Fastify();\n * await server.ready();\n * initSocket(server);\n * server.listen({ port: 3001 });\n */\nexport function initSocket(server: FastifyInstance): Server {\n io = new Server(server.server, {\n cors: {\n origin: process.env.WEBSOCKET_CORS_ORIGIN || 'http://localhost:3000',\n credentials: true,\n },\n });\n\n io.on('connection', (socket: Socket) => {\n console.log(\\`Client connected: \\${socket.id}\\`);\n\n // ── Real-time messaging ────────────────────────────────────────\n socket.on('message', (payload: { room?: string; content: string }) => {\n const message = {\n senderId: socket.id,\n content: payload.content,\n timestamp: new Date().toISOString(),\n };\n\n if (payload.room) {\n socket.to(payload.room).emit('message', message);\n } else {\n socket.broadcast.emit('message', message);\n }\n });\n\n // ── Notifications ──────────────────────────────────────────────\n socket.on('notification', (payload: { targetUserId?: string; title: string; body: string }) => {\n const notification = {\n title: payload.title,\n body: payload.body,\n timestamp: new Date().toISOString(),\n };\n\n if (payload.targetUserId) {\n io.to(\\`user:\\${payload.targetUserId}\\`).emit('notification', notification);\n } else {\n io.emit('notification', notification);\n }\n });\n\n // ── Room management ────────────────────────────────────────────\n socket.on('joinRoom', (payload: { room: string }) => {\n socket.join(payload.room);\n console.log(\\`Client \\${socket.id} joined room \\${payload.room}\\`);\n socket.to(payload.room).emit('roomEvent', {\n type: 'joined',\n clientId: socket.id,\n room: payload.room,\n });\n });\n\n socket.on('leaveRoom', (payload: { room: string }) => {\n socket.leave(payload.room);\n console.log(\\`Client \\${socket.id} left room \\${payload.room}\\`);\n socket.to(payload.room).emit('roomEvent', {\n type: 'left',\n clientId: socket.id,\n room: payload.room,\n });\n });\n\n // ── Disconnect ─────────────────────────────────────────────────\n socket.on('disconnect', (reason: string) => {\n console.log(\\`Client disconnected: \\${socket.id} (\\${reason})\\`);\n });\n });\n\n return io;\n}\n\n/** Get the Socket.IO instance (available after initSocket) */\nexport function getIO(): Server {\n if (!io) {\n throw new Error('Socket.IO has not been initialized. Call initSocket(server) first.');\n }\n return io;\n}\n\n/** Send an event to a specific user room */\nexport function sendToUser(userId: string, event: string, data: unknown) {\n getIO().to(\\`user:\\${userId}\\`).emit(event, data);\n}\n\n/** Send an event to a specific room */\nexport function sendToRoom(room: string, event: string, data: unknown) {\n getIO().to(room).emit(event, data);\n}\n\n/** Broadcast an event to all connected clients */\nexport function broadcast(event: string, data: unknown) {\n getIO().emit(event, data);\n}\n`);\n }\n\n // ── Dependencies (all backends) ───────────────────────────────────\n dependencies['socket.io'] = deps['socket.io'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\nimport { readPackageJson, writePackageJson, sortDeps } from '../../helpers/packages.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\n// ── Shared translation files ───────────────────────────────────────────────\n\nconst ptBR = JSON.stringify({\n common: {\n welcome: 'Bem-vindo',\n login: 'Entrar',\n register: 'Criar conta',\n dashboard: 'Painel',\n settings: 'Configurações',\n logout: 'Sair',\n save: 'Salvar',\n cancel: 'Cancelar',\n delete: 'Excluir',\n edit: 'Editar',\n loading: 'Carregando...',\n error: 'Ocorreu um erro',\n success: 'Operação realizada com sucesso',\n },\n auth: {\n loginTitle: 'Faça login na sua conta',\n registerTitle: 'Crie sua conta',\n forgotPassword: 'Esqueceu a senha?',\n emailPlaceholder: 'seu@email.com',\n passwordPlaceholder: 'Sua senha',\n },\n}, null, 2) + '\\n';\n\nconst en = JSON.stringify({\n common: {\n welcome: 'Welcome',\n login: 'Sign in',\n register: 'Sign up',\n dashboard: 'Dashboard',\n settings: 'Settings',\n logout: 'Sign out',\n save: 'Save',\n cancel: 'Cancel',\n delete: 'Delete',\n edit: 'Edit',\n loading: 'Loading...',\n error: 'An error occurred',\n success: 'Operation completed successfully',\n },\n auth: {\n loginTitle: 'Sign in to your account',\n registerTitle: 'Create your account',\n forgotPassword: 'Forgot password?',\n emailPlaceholder: 'you@email.com',\n passwordPlaceholder: 'Your password',\n },\n}, null, 2) + '\\n';\n\n// ── Installer ───────────────────────────────────────────────────────────────\n\nexport const i18nInstaller: InstallerFn = async (opts) => {\n const { config, webDir } = opts;\n\n switch (config.frontend) {\n case 'nextjs':\n await installNextIntl(webDir);\n break;\n case 'vue':\n await installVueI18n(webDir);\n break;\n case 'react-vite':\n await installReactI18next(webDir);\n break;\n case 'angular':\n await installAngularI18n(webDir);\n break;\n }\n};\n\n// ── Next.js (next-intl) ────────────────────────────────────────────────────\n\nasync function installNextIntl(webDir: string): Promise<void> {\n const pkg = await readPackageJson(webDir);\n if (!pkg.dependencies) pkg.dependencies = {};\n pkg.dependencies['next-intl'] = deps['next-intl'];\n await writePackageJson(webDir, sortDeps(pkg));\n\n await ensureDir(path.join(webDir, 'src', 'i18n'));\n await writeFile(path.join(webDir, 'src', 'i18n', 'request.ts'), `import { getRequestConfig } from 'next-intl/server';\nimport { routing } from './routing';\n\nexport default getRequestConfig(async ({ requestLocale }) => {\n let locale = await requestLocale;\n\n if (!locale || !routing.locales.includes(locale as any)) {\n locale = routing.defaultLocale;\n }\n\n return {\n locale,\n messages: (await import(\\`../messages/\\${locale}.json\\`)).default,\n };\n});\n`);\n\n await writeFile(path.join(webDir, 'src', 'i18n', 'routing.ts'), `import { defineRouting } from 'next-intl/routing';\nimport { createNavigation } from 'next-intl/navigation';\n\nexport const routing = defineRouting({\n locales: ['pt-BR', 'en'],\n defaultLocale: 'pt-BR',\n});\n\nexport const { Link, redirect, usePathname, useRouter } =\n createNavigation(routing);\n`);\n\n await ensureDir(path.join(webDir, 'src', 'messages'));\n await writeFile(path.join(webDir, 'src', 'messages', 'pt-BR.json'), ptBR);\n await writeFile(path.join(webDir, 'src', 'messages', 'en.json'), en);\n\n await writeFile(path.join(webDir, 'src', 'middleware.ts'), `import createMiddleware from 'next-intl/middleware';\nimport { routing } from './i18n/routing';\n\nexport default createMiddleware(routing);\n\nexport const config = {\n matcher: ['/', '/(pt-BR|en)/:path*'],\n};\n`);\n}\n\n// ── Vue (vue-i18n) ─────────────────────────────────────────────────────────\n\nasync function installVueI18n(webDir: string): Promise<void> {\n const pkg = await readPackageJson(webDir);\n if (!pkg.dependencies) pkg.dependencies = {};\n pkg.dependencies['vue-i18n'] = deps['vue-i18n'];\n await writePackageJson(webDir, sortDeps(pkg));\n\n await ensureDir(path.join(webDir, 'src', 'i18n'));\n await writeFile(path.join(webDir, 'src', 'i18n', 'index.ts'), `import { createI18n } from 'vue-i18n';\nimport ptBR from './locales/pt-BR.json';\nimport en from './locales/en.json';\n\nexport const i18n = createI18n({\n legacy: false,\n locale: 'pt-BR',\n fallbackLocale: 'en',\n messages: {\n 'pt-BR': ptBR,\n en,\n },\n});\n\nexport default i18n;\n`);\n\n await ensureDir(path.join(webDir, 'src', 'i18n', 'locales'));\n await writeFile(path.join(webDir, 'src', 'i18n', 'locales', 'pt-BR.json'), ptBR);\n await writeFile(path.join(webDir, 'src', 'i18n', 'locales', 'en.json'), en);\n}\n\n// ── React-Vite (i18next + react-i18next) ───────────────────────────────────\n\nasync function installReactI18next(webDir: string): Promise<void> {\n const pkg = await readPackageJson(webDir);\n if (!pkg.dependencies) pkg.dependencies = {};\n pkg.dependencies['i18next'] = deps['i18next'];\n pkg.dependencies['react-i18next'] = deps['react-i18next'];\n await writePackageJson(webDir, sortDeps(pkg));\n\n await ensureDir(path.join(webDir, 'src', 'i18n'));\n await writeFile(path.join(webDir, 'src', 'i18n', 'index.ts'), `import i18n from 'i18next';\nimport { initReactI18next } from 'react-i18next';\nimport ptBR from './locales/pt-BR.json';\nimport en from './locales/en.json';\n\ni18n.use(initReactI18next).init({\n resources: {\n 'pt-BR': { translation: ptBR },\n en: { translation: en },\n },\n lng: 'pt-BR',\n fallbackLng: 'en',\n interpolation: {\n escapeValue: false,\n },\n});\n\nexport default i18n;\n`);\n\n await ensureDir(path.join(webDir, 'src', 'i18n', 'locales'));\n await writeFile(path.join(webDir, 'src', 'i18n', 'locales', 'pt-BR.json'), ptBR);\n await writeFile(path.join(webDir, 'src', 'i18n', 'locales', 'en.json'), en);\n}\n\n// ── Angular (simple translation helper) ────────────────────────────────────\n\nasync function installAngularI18n(webDir: string): Promise<void> {\n await ensureDir(path.join(webDir, 'src', 'i18n'));\n\n await writeFile(path.join(webDir, 'src', 'i18n', 'translations.ts'), `import ptBR from './locales/pt-BR.json';\nimport en from './locales/en.json';\n\ntype Locale = 'pt-BR' | 'en';\n\nconst messages: Record<Locale, Record<string, any>> = {\n 'pt-BR': ptBR,\n en,\n};\n\nlet currentLocale: Locale = 'pt-BR';\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\n/**\n * Translate a dot-notation key for the given (or current) locale.\n *\n * Example: t('common.welcome') => 'Bem-vindo'\n */\nexport function t(key: string, locale?: Locale): string {\n const lang = locale ?? currentLocale;\n const parts = key.split('.');\n let result: any = messages[lang];\n\n for (const part of parts) {\n if (result == null) return key;\n result = result[part];\n }\n\n return typeof result === 'string' ? result : key;\n}\n\nexport default { t, setLocale, getLocale };\n`);\n\n await ensureDir(path.join(webDir, 'src', 'i18n', 'locales'));\n await writeFile(path.join(webDir, 'src', 'i18n', 'locales', 'pt-BR.json'), ptBR);\n await writeFile(path.join(webDir, 'src', 'i18n', 'locales', 'en.json'), en);\n}\n","import type { ProjectConfig } from '../types/config.js';\nimport type { InstallerMap } from '../types/installers.js';\n\nimport { prismaInstaller } from './database/prisma.js';\nimport { mongooseInstaller } from './database/mongoose.js';\nimport { jwtInstaller } from './auth/jwt.js';\nimport { magicLinkInstaller } from './auth/magicLink.js';\nimport { googleOauthInstaller } from './auth/googleOauth.js';\nimport { bullmqInstaller } from './queue/bullmq.js';\nimport { rabbitmqInstaller } from './queue/rabbitmq.js';\nimport { redisInstaller } from './infra/redis.js';\nimport { smtpInstaller } from './infra/smtp.js';\nimport { minioInstaller } from './infra/minio.js';\nimport { pm2Installer } from './infra/pm2.js';\nimport { multiTenantInstaller } from './multiTenant.js';\nimport { viacepInstaller } from './integrations/viacep.js';\nimport { whatsappInstaller } from './integrations/whatsapp.js';\nimport { stripeInstaller } from './integrations/stripe.js';\nimport { mercadoPagoInstaller } from './integrations/mercadoPago.js';\nimport { abacatePayInstaller } from './integrations/abacatePay.js';\n\n// New v1.1+ installers\nimport { zodInstaller } from './api/zod.js';\nimport { rateLimitingInstaller } from './api/rateLimiting.js';\nimport { loggingInstaller } from './api/logging.js';\nimport { swaggerInstaller } from './api/swagger.js';\nimport { rbacInstaller } from './saas/rbac.js';\nimport { organizationsInstaller } from './saas/organizations.js';\nimport { stripeBillingInstaller } from './saas/stripeBilling.js';\nimport { websocketsInstaller } from './infra/websockets.js';\nimport { i18nInstaller } from './infra/i18n.js';\n\nexport function buildInstallerMap(config: ProjectConfig): InstallerMap {\n return {\n // Database (must run before auth since auth may depend on user model)\n 'Prisma': {\n inUse: config.usePrisma,\n installer: prismaInstaller,\n },\n 'Mongoose': {\n inUse: config.useMongoose,\n installer: mongooseInstaller,\n },\n\n // Multi-tenant (after database)\n 'Multi-tenant': {\n inUse: config.multiTenant,\n installer: multiTenantInstaller,\n },\n\n // Infrastructure\n 'Redis': {\n inUse: config.redis,\n installer: redisInstaller,\n },\n 'SMTP': {\n inUse: config.smtp,\n installer: smtpInstaller,\n },\n 'MinIO': {\n inUse: config.minio,\n installer: minioInstaller,\n },\n 'PM2': {\n inUse: config.pm2,\n installer: pm2Installer,\n },\n 'WebSockets': {\n inUse: config.websockets,\n installer: websocketsInstaller,\n },\n\n // Auth\n 'JWT Auth': {\n inUse: config.auth.jwt,\n installer: jwtInstaller,\n },\n 'Magic Link': {\n inUse: config.auth.magicLink,\n installer: magicLinkInstaller,\n },\n 'Google OAuth': {\n inUse: config.auth.googleOAuth,\n installer: googleOauthInstaller,\n },\n\n // SaaS Features\n 'RBAC': {\n inUse: config.rbac,\n installer: rbacInstaller,\n },\n 'Organizations': {\n inUse: config.organizations,\n installer: organizationsInstaller,\n },\n 'Stripe Billing': {\n inUse: config.stripeBilling,\n installer: stripeBillingInstaller,\n },\n\n // API Quality\n 'Zod Validation': {\n inUse: config.zod,\n installer: zodInstaller,\n },\n 'Rate Limiting': {\n inUse: config.rateLimiting,\n installer: rateLimitingInstaller,\n },\n 'Logging (Pino)': {\n inUse: config.logging,\n installer: loggingInstaller,\n },\n 'Swagger/OpenAPI': {\n inUse: config.swagger,\n installer: swaggerInstaller,\n },\n\n // i18n\n 'i18n': {\n inUse: config.i18n,\n installer: i18nInstaller,\n },\n\n // Queues\n 'BullMQ': {\n inUse: config.queue === 'bullmq',\n installer: bullmqInstaller,\n },\n 'RabbitMQ': {\n inUse: config.queue === 'rabbitmq',\n installer: rabbitmqInstaller,\n },\n\n // Integrations\n 'ViaCEP': {\n inUse: config.integrations.viacep,\n installer: viacepInstaller,\n },\n 'WhatsApp': {\n inUse: config.integrations.whatsapp,\n installer: whatsappInstaller,\n },\n 'Stripe': {\n inUse: config.integrations.stripe && !config.stripeBilling,\n installer: stripeInstaller,\n },\n 'Mercado Pago': {\n inUse: config.integrations.mercadoPago,\n installer: mercadoPagoInstaller,\n },\n 'AbacatePay': {\n inUse: config.integrations.abacatePay,\n installer: abacatePayInstaller,\n },\n };\n}\n","import ora, { type Ora } from 'ora';\n\nexport function createSpinner(text: string): Ora {\n return ora({ text, color: 'cyan' });\n}\n\nexport async function withSpinner<T>(text: string, fn: () => Promise<T>): Promise<T> {\n const spinner = createSpinner(text);\n spinner.start();\n try {\n const result = await fn();\n spinner.succeed();\n return result;\n } catch (error) {\n spinner.fail();\n throw error;\n }\n}\n","import { execa } from 'execa';\n\nexport async function initGit(projectDir: string): Promise<void> {\n await execa('git', ['init'], { cwd: projectDir });\n await execa('git', ['add', '-A'], { cwd: projectDir });\n await execa('git', ['commit', '-m', 'chore: initial commit from plazercli'], {\n cwd: projectDir,\n });\n}\n","import { parseArgs } from './cli/args.js';\nimport { runPrompts } from './cli/prompts.js';\nimport { printBanner, printSummary, logger } from './helpers/logger.js';\nimport { generateProject } from './generators/project.js';\nimport { confirm } from '@inquirer/prompts';\nimport type { ProjectConfig } from './types/config.js';\nimport chalk from 'chalk';\nimport fs from 'fs-extra';\n\nasync function main() {\n const flags = parseArgs();\n\n printBanner();\n const config = await runPrompts(flags);\n\n // --save-config: save config to file\n if (flags.saveConfig) {\n const configToSave = { ...config };\n delete (configToSave as Record<string, unknown>).projectDir;\n await fs.writeFile(flags.saveConfig, JSON.stringify(configToSave, null, 2), 'utf-8');\n logger.success(`Configuracao salva em ${flags.saveConfig}`);\n }\n\n printSummary(config);\n\n // --dry-run: show what would be generated without creating files\n if (flags.dryRun) {\n printDryRun(config);\n return;\n }\n\n const confirmed = flags.yes || await confirm({\n message: 'Confirma a criacao do projeto com essas configuracoes?',\n default: true,\n });\n\n if (!confirmed) {\n logger.warn('Criacao cancelada.');\n process.exit(0);\n }\n\n await generateProject(config);\n}\n\nfunction printDryRun(config: ProjectConfig): void {\n console.log(chalk.bold.yellow('\\n --- DRY RUN (nenhum arquivo sera criado) ---\\n'));\n\n const features: string[] = [];\n\n features.push(`apps/api/ (${config.backend})`);\n features.push(`apps/web/ (${config.frontend})`);\n\n if (config.database !== 'none') features.push(`Banco: ${config.database}`);\n if (config.usePrisma) features.push('prisma/schema.prisma');\n if (config.rbac) features.push('src/rbac/ (roles + guards)');\n if (config.organizations) features.push('src/organizations/ (CRUD + convites)');\n if (config.stripeBilling) features.push('src/billing/ (Stripe subscriptions)');\n if (config.zod) features.push('src/common/validation/ (Zod schemas)');\n if (config.rateLimiting) features.push('Rate limiting middleware');\n if (config.logging) features.push('Pino structured logging');\n if (config.swagger) features.push('Swagger/OpenAPI em /api/docs');\n if (config.redis) features.push('Redis (ioredis)');\n if (config.smtp) features.push('SMTP email service');\n if (config.websockets) features.push('WebSockets (Socket.IO)');\n if (config.tailwind) features.push('Tailwind CSS + paginas SaaS');\n if (config.cicd) features.push('GitHub Actions + Dockerfiles');\n if (config.minio) features.push('MinIO storage');\n if (config.pm2) features.push('PM2 ecosystem config');\n if (config.i18n) features.push('i18n (pt-BR + en)');\n\n features.push('docker-compose.yml');\n features.push('.env + .env.example');\n features.push('README.md');\n features.push('CLAUDE.md + AGENTS.md (Liz AI)');\n\n console.log(chalk.white(' Arquivos e features que seriam gerados:\\n'));\n for (const f of features) {\n console.log(chalk.cyan(' + ') + chalk.white(f));\n }\n console.log(chalk.bold.yellow('\\n Rode sem --dry-run para criar o projeto.\\n'));\n}\n\nmain().catch((error) => {\n logger.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n});\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8O/B,IAAM,4BAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0IlC,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkB9B,IAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyNhC,IAAM,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuI/B,IAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuNhC,IAAM,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["path","fileURLToPath","__dirname","path","path","fs","projectDescription","path","chalk","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","pkg","pkg","pkg","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","pkg","path","execa","path","chalk","confirm","chalk","fs"]}