plazercli 2.0.0 → 3.1.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/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"]}
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/auth/githubOauth.ts","../src/installers/auth/appleSignIn.ts","../src/installers/auth/discordOauth.ts","../src/installers/auth/clerk.ts","../src/installers/auth/nextAuth.ts","../src/installers/security/totp.ts","../src/installers/monitoring/sentry.ts","../src/installers/infra/resend.ts","../src/installers/infra/awsS3.ts","../src/installers/infra/cloudflareR2.ts","../src/installers/api/trpc.ts","../src/installers/integrations/twilioSms.ts","../src/installers/integrations/telegramBot.ts","../src/installers/integrations/openai.ts","../src/installers/integrations/vercelAi.ts","../src/installers/integrations/paypal.ts","../src/installers/testing/vitest.ts","../src/installers/analytics/googleAnalytics.ts","../src/installers/search/meilisearch.ts","../src/installers/scheduling/nodeCron.ts","../src/installers/pdf/pdfkit.ts","../src/installers/misc/healthChecks.ts","../src/installers/auth/facebookOauth.ts","../src/installers/auth/microsoftOauth.ts","../src/installers/auth/linkedinOauth.ts","../src/installers/auth/twitterOauth.ts","../src/installers/auth/spotifyOauth.ts","../src/installers/auth/auth0.ts","../src/installers/auth/supabaseAuth.ts","../src/installers/infra/sendgrid.ts","../src/installers/infra/amazonSes.ts","../src/installers/analytics/posthog.ts","../src/installers/analytics/plausible.ts","../src/installers/analytics/mixpanel.ts","../src/installers/search/algolia.ts","../src/installers/search/elasticsearch.ts","../src/installers/search/typesense.ts","../src/installers/api/graphql.ts","../src/installers/security/recaptcha.ts","../src/installers/testing/playwright.ts","../src/installers/scheduling/inngest.ts","../src/installers/pdf/puppeteer.ts","../src/installers/cms/strapi.ts","../src/installers/cms/sanity.ts","../src/installers/integrations/paddle.ts","../src/installers/integrations/lemonSqueezy.ts","../src/installers/integrations/pagSeguro.ts","../src/installers/integrations/asaas.ts","../src/installers/integrations/anthropic.ts","../src/installers/integrations/googleGemini.ts","../src/installers/integrations/langchain.ts","../src/installers/integrations/slackWebhook.ts","../src/installers/integrations/discordWebhook.ts","../src/installers/integrations/firebaseFcm.ts","../src/installers/integrations/oneSignal.ts","../src/installers/integrations/mapbox.ts","../src/installers/integrations/hotjar.ts","../src/installers/integrations/cloudinary.ts","../src/installers/integrations/uploadThing.ts","../src/installers/integrations/googleMaps.ts","../src/installers/baas/supabase.ts","../src/installers/baas/firebase.ts","../src/installers/baas/neonDb.ts","../src/installers/baas/upstashRedis.ts","../src/installers/featureFlags/flagsmith.ts","../src/installers/featureFlags/launchDarkly.ts","../src/installers/misc/compression.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: {\n jwt: true, magicLink: false, googleOAuth: false, githubOAuth: false, appleSignIn: false, discordOAuth: false,\n facebookOAuth: false, microsoftOAuth: false, linkedinOAuth: false, twitterOAuth: false, spotifyOAuth: false,\n },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: {\n viacep: false, whatsapp: false, stripe: false, mercadoPago: false, abacatePay: false,\n paypal: false, openai: false, vercelAi: false, twilioSms: false, telegramBot: false, googleMaps: false,\n paddle: false, lemonSqueezy: false, pagSeguro: false, asaas: false,\n anthropic: false, googleGemini: false, langchain: false,\n slackWebhook: false, discordWebhook: false, firebaseFcm: false, oneSignal: false,\n mapbox: false, hotjar: false, cloudinary: false, uploadThing: false,\n },\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 clerk: false,\n nextAuth: false,\n auth0: false,\n supabaseAuth: false,\n resend: false,\n sendgrid: false,\n amazonSes: false,\n awsS3: false,\n cloudflareR2: false,\n sentry: false,\n googleAnalytics: false,\n posthog: false,\n plausible: false,\n mixpanel: false,\n trpc: false,\n graphql: false,\n totp: false,\n recaptcha: false,\n vitest: false,\n playwright: false,\n meilisearch: false,\n algolia: false,\n elasticsearch: false,\n typesense: false,\n nodeCron: false,\n inngest: false,\n pdfkit: false,\n puppeteer: false,\n strapi: false,\n sanity: false,\n supabase: false,\n firebase: false,\n neonDb: false,\n upstashRedis: false,\n flagsmith: false,\n launchDarkly: false,\n healthChecks: true,\n compression: 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 // ═══════════════════════════════════════════\n // STEP 1/8 — Stack Principal\n // ═══════════════════════════════════════════\n\n if (!useYes) console.log('\\n ── Step 1/8: Stack Principal ──\\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 // ═══════════════════════════════════════════\n // STEP 2/8 — Autenticacao (11 OAuth + 5 services)\n // ═══════════════════════════════════════════\n\n if (!useYes) console.log('\\n ── Step 2/8: Autenticacao ──\\n');\n\n // 8. Metodos de autenticacao (11 providers)\n const authChoices = useYes\n ? ['jwt']\n : await checkbox({\n message: '🔐 Quais metodos de autenticacao usar? (11 opcoes)',\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 { name: 'GitHub OAuth', value: 'githubOAuth' },\n { name: 'Apple Sign-In', value: 'appleSignIn' },\n { name: 'Discord OAuth', value: 'discordOAuth' },\n { name: 'Facebook OAuth', value: 'facebookOAuth' },\n { name: 'Microsoft/Azure OAuth', value: 'microsoftOAuth' },\n { name: 'LinkedIn OAuth', value: 'linkedinOAuth' },\n { name: 'Twitter/X OAuth', value: 'twitterOAuth' },\n { name: 'Spotify OAuth', value: 'spotifyOAuth' },\n ],\n });\n\n const auth = {\n jwt: authChoices.includes('jwt'),\n magicLink: authChoices.includes('magicLink'),\n googleOAuth: authChoices.includes('googleOAuth'),\n githubOAuth: authChoices.includes('githubOAuth'),\n appleSignIn: authChoices.includes('appleSignIn'),\n discordOAuth: authChoices.includes('discordOAuth'),\n facebookOAuth: authChoices.includes('facebookOAuth'),\n microsoftOAuth: authChoices.includes('microsoftOAuth'),\n linkedinOAuth: authChoices.includes('linkedinOAuth'),\n twitterOAuth: authChoices.includes('twitterOAuth'),\n spotifyOAuth: authChoices.includes('spotifyOAuth'),\n };\n\n // 9. Auth services (5 opcoes)\n let clerk = false;\n let nextAuth = false;\n let auth0 = false;\n let supabaseAuth = false;\n let totp = false;\n\n if (!useYes) {\n const authServices = await checkbox({\n message: '🛡️ Servicos de autenticacao adicionais? (5 opcoes)',\n choices: [\n { name: 'Clerk (auth completo com UI pronto)', value: 'clerk' },\n { name: 'NextAuth/Auth.js (auth nativo Next.js)', value: 'nextAuth' },\n { name: 'Auth0 (auth enterprise)', value: 'auth0' },\n { name: 'Supabase Auth (auth open-source)', value: 'supabaseAuth' },\n { name: '2FA/TOTP (autenticacao de dois fatores)', value: 'totp' },\n ],\n });\n clerk = authServices.includes('clerk');\n nextAuth = authServices.includes('nextAuth');\n auth0 = authServices.includes('auth0');\n supabaseAuth = authServices.includes('supabaseAuth');\n totp = authServices.includes('totp');\n }\n\n // ═══════════════════════════════════════════\n // STEP 3/8 — SaaS Features\n // ═══════════════════════════════════════════\n\n if (!useYes) console.log('\\n ── Step 3/8: SaaS Features ──\\n');\n\n // 10. 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 // ═══════════════════════════════════════════\n // STEP 4/8 — API Quality & Patterns\n // ═══════════════════════════════════════════\n\n if (!useYes) console.log('\\n ── Step 4/8: API Quality & Patterns ──\\n');\n\n // 11. API Quality (8 opcoes)\n let zod = false;\n let rateLimiting = false;\n let logging = false;\n let swagger = false;\n let trpc = false;\n let graphql = false;\n let healthChecks = true;\n let compression = false;\n\n if (!useYes) {\n const apiFeatures = await checkbox({\n message: '🛡️ Quais features de API incluir? (8 opcoes)',\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 { name: 'tRPC (API typesafe end-to-end)', value: 'trpc' },\n { name: 'GraphQL (Apollo Server)', value: 'graphql' },\n { name: 'Health Checks (/api/health)', value: 'healthChecks', checked: true },\n { name: 'Compression (gzip/brotli)', value: 'compression' },\n ],\n });\n zod = apiFeatures.includes('zod');\n rateLimiting = apiFeatures.includes('rateLimiting');\n logging = apiFeatures.includes('logging');\n swagger = apiFeatures.includes('swagger');\n trpc = apiFeatures.includes('trpc');\n graphql = apiFeatures.includes('graphql');\n healthChecks = apiFeatures.includes('healthChecks');\n compression = apiFeatures.includes('compression');\n } else {\n zod = defaults.zod;\n rateLimiting = defaults.rateLimiting;\n logging = defaults.logging;\n swagger = defaults.swagger;\n trpc = defaults.trpc;\n graphql = defaults.graphql;\n healthChecks = defaults.healthChecks;\n compression = defaults.compression;\n }\n\n // ═══════════════════════════════════════════\n // STEP 5/8 — Infraestrutura\n // ═══════════════════════════════════════════\n\n if (!useYes) console.log('\\n ── Step 5/8: Infraestrutura ──\\n');\n\n // 12. Multi-tenant\n const multiTenant = useYes\n ? defaults.multiTenant\n : await confirm({\n message: '🏢 Usar multi-tenant?',\n default: false,\n });\n\n // 13. Email (4 opcoes - checkbox para multiplos)\n let smtp = false;\n let resend = false;\n let sendgrid = false;\n let amazonSes = false;\n\n if (!useYes) {\n const emailChoices = await checkbox({\n message: '📧 Quais servicos de email usar? (4 opcoes)',\n choices: [\n { name: 'SMTP (Nodemailer)', value: 'smtp' },\n { name: 'Resend (API moderna)', value: 'resend' },\n { name: 'SendGrid', value: 'sendgrid' },\n { name: 'Amazon SES', value: 'amazonSes' },\n ],\n });\n smtp = emailChoices.includes('smtp');\n resend = emailChoices.includes('resend');\n sendgrid = emailChoices.includes('sendgrid');\n amazonSes = emailChoices.includes('amazonSes');\n } else {\n smtp = defaults.smtp;\n resend = defaults.resend;\n sendgrid = defaults.sendgrid;\n amazonSes = defaults.amazonSes;\n }\n\n // Auto-habilitar email se Magic Link selecionado\n if (auth.magicLink && !smtp && !resend && !sendgrid && !amazonSes) {\n smtp = true;\n console.log(' ℹ SMTP habilitado automaticamente (necessario para Magic Link)');\n }\n\n // 14. Redis\n let redis = useYes\n ? defaults.redis\n : await confirm({\n message: '🔴 Usar Redis (cache/sessoes)?',\n default: true,\n });\n\n // 15. 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 // 16. Storage (5 opcoes - checkbox para multiplos)\n let minio = false;\n let awsS3 = false;\n let cloudflareR2 = false;\n let storageCloudinary = false;\n let storageUploadThing = false;\n\n if (!useYes) {\n const storageChoices = await checkbox({\n message: '📦 Quais storage usar para arquivos? (5 opcoes)',\n choices: [\n { name: 'MinIO (S3-compatible local)', value: 'minio' },\n { name: 'AWS S3', value: 's3' },\n { name: 'Cloudflare R2 (sem egress fees)', value: 'r2' },\n { name: 'Cloudinary (imagens/videos na nuvem)', value: 'cloudinary' },\n { name: 'UploadThing (upload simplificado)', value: 'uploadThing' },\n ],\n });\n minio = storageChoices.includes('minio');\n awsS3 = storageChoices.includes('s3');\n cloudflareR2 = storageChoices.includes('r2');\n storageCloudinary = storageChoices.includes('cloudinary');\n storageUploadThing = storageChoices.includes('uploadThing');\n } else {\n minio = defaults.minio;\n awsS3 = defaults.awsS3;\n cloudflareR2 = defaults.cloudflareR2;\n }\n\n // 17. Search (4 opcoes)\n let meilisearch = false;\n let algolia = false;\n let elasticsearch = false;\n let typesense = false;\n\n if (!useYes) {\n const searchChoices = await checkbox({\n message: '🔍 Quais motores de busca usar? (4 opcoes)',\n choices: [\n { name: 'Meilisearch (open-source, rapido)', value: 'meilisearch' },\n { name: 'Algolia (search-as-a-service)', value: 'algolia' },\n { name: 'Elasticsearch (enterprise)', value: 'elasticsearch' },\n { name: 'Typesense (open-source, typo-tolerant)', value: 'typesense' },\n ],\n });\n meilisearch = searchChoices.includes('meilisearch');\n algolia = searchChoices.includes('algolia');\n elasticsearch = searchChoices.includes('elasticsearch');\n typesense = searchChoices.includes('typesense');\n }\n\n // 18. Scheduling (2 opcoes)\n let nodeCron = false;\n let inngest = false;\n\n if (!useYes) {\n const schedChoices = await checkbox({\n message: '⏰ Tarefas agendadas? (2 opcoes)',\n choices: [\n { name: 'node-cron (cron jobs simples)', value: 'nodeCron' },\n { name: 'Inngest (event-driven background jobs)', value: 'inngest' },\n ],\n });\n nodeCron = schedChoices.includes('nodeCron');\n inngest = schedChoices.includes('inngest');\n }\n\n // ═══════════════════════════════════════════\n // STEP 6/8 — Integracoes (40+ opcoes)\n // ═══════════════════════════════════════════\n\n if (!useYes) console.log('\\n ── Step 6/8: Integracoes ──\\n');\n\n // 19. Pagamentos (8 gateways)\n const paymentChoices = useYes\n ? []\n : await checkbox({\n message: '💳 Quais gateways de pagamento usar? (8 opcoes)',\n choices: [\n { name: 'Stripe', value: 'stripe' },\n { name: 'PayPal', value: 'paypal' },\n { name: 'Mercado Pago', value: 'mercadoPago' },\n { name: 'AbacatePay', value: 'abacatePay' },\n { name: 'Paddle', value: 'paddle' },\n { name: 'Lemon Squeezy', value: 'lemonSqueezy' },\n { name: 'PagSeguro', value: 'pagSeguro' },\n { name: 'Asaas', value: 'asaas' },\n ],\n });\n\n // 20. Comunicacao (7 canais)\n const commChoices = useYes\n ? []\n : await checkbox({\n message: '💬 Quais integracoes de comunicacao? (7 opcoes)',\n choices: [\n { name: 'WhatsApp (Meta Business)', value: 'whatsapp' },\n { name: 'Twilio SMS', value: 'twilioSms' },\n { name: 'Telegram Bot', value: 'telegramBot' },\n { name: 'Slack Webhook', value: 'slackWebhook' },\n { name: 'Discord Webhook', value: 'discordWebhook' },\n { name: 'Firebase Cloud Messaging (push)', value: 'firebaseFcm' },\n { name: 'OneSignal (push notifications)', value: 'oneSignal' },\n ],\n });\n\n // 21. AI (5 opcoes)\n const aiChoices = useYes\n ? []\n : await checkbox({\n message: '🤖 Integracoes de IA? (5 opcoes)',\n choices: [\n { name: 'OpenAI (GPT, embeddings, assistants)', value: 'openai' },\n { name: 'Vercel AI SDK (SDK unificado)', value: 'vercelAi' },\n { name: 'Anthropic (Claude)', value: 'anthropic' },\n { name: 'Google Gemini', value: 'googleGemini' },\n { name: 'LangChain (framework de IA)', value: 'langchain' },\n ],\n });\n\n // 22. Outras integracoes (4 opcoes)\n const otherIntChoices = useYes\n ? []\n : await checkbox({\n message: '🔌 Outras integracoes? (4 opcoes)',\n choices: [\n { name: 'ViaCEP (consulta CEP)', value: 'viacep' },\n { name: 'Google Maps', value: 'googleMaps' },\n { name: 'Mapbox (mapas e geocoding)', value: 'mapbox' },\n { name: 'Hotjar (heatmaps e gravacoes)', value: 'hotjar' },\n ],\n });\n\n const integrations = {\n viacep: otherIntChoices.includes('viacep'),\n whatsapp: commChoices.includes('whatsapp'),\n stripe: paymentChoices.includes('stripe') || stripeBilling,\n mercadoPago: paymentChoices.includes('mercadoPago'),\n abacatePay: paymentChoices.includes('abacatePay'),\n paypal: paymentChoices.includes('paypal'),\n openai: aiChoices.includes('openai'),\n vercelAi: aiChoices.includes('vercelAi'),\n twilioSms: commChoices.includes('twilioSms'),\n telegramBot: commChoices.includes('telegramBot'),\n googleMaps: otherIntChoices.includes('googleMaps'),\n // v3.1 integrations\n paddle: paymentChoices.includes('paddle'),\n lemonSqueezy: paymentChoices.includes('lemonSqueezy'),\n pagSeguro: paymentChoices.includes('pagSeguro'),\n asaas: paymentChoices.includes('asaas'),\n anthropic: aiChoices.includes('anthropic'),\n googleGemini: aiChoices.includes('googleGemini'),\n langchain: aiChoices.includes('langchain'),\n slackWebhook: commChoices.includes('slackWebhook'),\n discordWebhook: commChoices.includes('discordWebhook'),\n firebaseFcm: commChoices.includes('firebaseFcm'),\n oneSignal: commChoices.includes('oneSignal'),\n mapbox: otherIntChoices.includes('mapbox'),\n hotjar: otherIntChoices.includes('hotjar'),\n cloudinary: storageCloudinary || false,\n uploadThing: storageUploadThing || false,\n };\n\n // ═══════════════════════════════════════════\n // STEP 7/8 — Monitoring, Analytics & Security\n // ═══════════════════════════════════════════\n\n if (!useYes) console.log('\\n ── Step 7/8: Monitoring, Analytics & Security ──\\n');\n\n // 23. Monitoring & Analytics (5 opcoes)\n let sentry = false;\n let googleAnalytics = false;\n let posthog = false;\n let plausible = false;\n let mixpanel = false;\n\n if (!useYes) {\n const monitoringChoices = await checkbox({\n message: '📊 Monitoring & Analytics? (5 opcoes)',\n choices: [\n { name: 'Sentry (error tracking + performance)', value: 'sentry' },\n { name: 'Google Analytics 4', value: 'googleAnalytics' },\n { name: 'PostHog (product analytics open-source)', value: 'posthog' },\n { name: 'Plausible (privacy-first analytics)', value: 'plausible' },\n { name: 'Mixpanel (event analytics)', value: 'mixpanel' },\n ],\n });\n sentry = monitoringChoices.includes('sentry');\n googleAnalytics = monitoringChoices.includes('googleAnalytics');\n posthog = monitoringChoices.includes('posthog');\n plausible = monitoringChoices.includes('plausible');\n mixpanel = monitoringChoices.includes('mixpanel');\n }\n\n // 24. Security (1 opcao alem do TOTP que ja esta em auth)\n let recaptcha = false;\n if (!useYes) {\n recaptcha = await confirm({\n message: '🔒 Usar reCAPTCHA (protecao contra bots)?',\n default: false,\n });\n }\n\n // ═══════════════════════════════════════════\n // STEP 8/8 — Extras (20+ opcoes)\n // ═══════════════════════════════════════════\n\n if (!useYes) console.log('\\n ── Step 8/8: Extras ──\\n');\n\n // 25. Testing (2 opcoes)\n let vitest = false;\n let playwright = false;\n\n if (!useYes) {\n const testChoices = await checkbox({\n message: '🧪 Quais ferramentas de teste? (2 opcoes)',\n choices: [\n { name: 'Vitest + Supertest (unit + HTTP)', value: 'vitest' },\n { name: 'Playwright (E2E browser tests)', value: 'playwright' },\n ],\n });\n vitest = testChoices.includes('vitest');\n playwright = testChoices.includes('playwright');\n }\n\n // 26. PDF (2 opcoes)\n let pdfkit = false;\n let puppeteer = false;\n\n if (!useYes) {\n const pdfChoices = await checkbox({\n message: '📄 Geracao de PDF? (2 opcoes)',\n choices: [\n { name: 'PDFKit (gerar PDFs programaticamente)', value: 'pdfkit' },\n { name: 'Puppeteer (PDF via HTML/screenshot)', value: 'puppeteer' },\n ],\n });\n pdfkit = pdfChoices.includes('pdfkit');\n puppeteer = pdfChoices.includes('puppeteer');\n }\n\n // 27. CMS (2 opcoes)\n let strapi = false;\n let sanity = false;\n\n if (!useYes) {\n const cmsChoices = await checkbox({\n message: '📝 CMS (Content Management)? (2 opcoes)',\n choices: [\n { name: 'Strapi (headless CMS open-source)', value: 'strapi' },\n { name: 'Sanity (structured content platform)', value: 'sanity' },\n ],\n });\n strapi = cmsChoices.includes('strapi');\n sanity = cmsChoices.includes('sanity');\n }\n\n // 28. BaaS (4 opcoes)\n let supabase = false;\n let firebase = false;\n let neonDb = false;\n let upstashRedis = false;\n\n if (!useYes) {\n const baasChoices = await checkbox({\n message: '☁️ Backend-as-a-Service? (4 opcoes)',\n choices: [\n { name: 'Supabase (Postgres + Auth + Storage)', value: 'supabase' },\n { name: 'Firebase (Firestore + Auth + FCM)', value: 'firebase' },\n { name: 'Neon DB (serverless Postgres)', value: 'neonDb' },\n { name: 'Upstash Redis (serverless Redis)', value: 'upstashRedis' },\n ],\n });\n supabase = baasChoices.includes('supabase');\n firebase = baasChoices.includes('firebase');\n neonDb = baasChoices.includes('neonDb');\n upstashRedis = baasChoices.includes('upstashRedis');\n }\n\n // 29. Feature Flags (2 opcoes)\n let flagsmith = false;\n let launchDarkly = false;\n\n if (!useYes) {\n const ffChoices = await checkbox({\n message: '🚩 Feature Flags? (2 opcoes)',\n choices: [\n { name: 'Flagsmith (open-source)', value: 'flagsmith' },\n { name: 'LaunchDarkly (enterprise)', value: 'launchDarkly' },\n ],\n });\n flagsmith = ffChoices.includes('flagsmith');\n launchDarkly = ffChoices.includes('launchDarkly');\n }\n\n // 30. Extras gerais\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 gerais?',\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 // 31. 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 clerk,\n nextAuth,\n auth0,\n supabaseAuth,\n resend,\n sendgrid,\n amazonSes,\n awsS3,\n cloudflareR2,\n sentry,\n googleAnalytics,\n posthog,\n plausible,\n mixpanel,\n trpc,\n graphql,\n totp,\n recaptcha,\n vitest,\n playwright,\n meilisearch,\n algolia,\n elasticsearch,\n typesense,\n nodeCron,\n inngest,\n pdfkit,\n puppeteer,\n strapi,\n sanity,\n supabase,\n firebase,\n neonDb,\n upstashRedis,\n flagsmith,\n launchDarkly,\n healthChecks,\n compression,\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 || partial.auth.githubOAuth || partial.auth.appleSignIn || partial.auth.discordOAuth || partial.auth.facebookOAuth || partial.auth.microsoftOAuth || partial.auth.linkedinOAuth || partial.auth.twitterOAuth || partial.auth.spotifyOAuth || partial.clerk || partial.nextAuth || partial.auth0 || partial.supabaseAuth,\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\n// v3.0 defaults for new fields (all off by default)\nconst v3Defaults = {\n clerk: false,\n nextAuth: false,\n resend: false,\n awsS3: false,\n cloudflareR2: false,\n sentry: false,\n googleAnalytics: false,\n trpc: false,\n totp: false,\n vitest: false,\n meilisearch: false,\n nodeCron: false,\n pdfkit: false,\n healthChecks: true,\n} as const;\n\n// v3.0 auth defaults\nconst v3AuthDefaults = {\n githubOAuth: false,\n appleSignIn: false,\n discordOAuth: false,\n} as const;\n\n// v3.0 integration defaults\nconst v3IntegrationDefaults = {\n paypal: false,\n openai: false,\n vercelAi: false,\n twilioSms: false,\n telegramBot: false,\n googleMaps: false,\n} as const;\n\n// v3.1 auth defaults\nconst v31AuthDefaults = {\n facebookOAuth: false,\n microsoftOAuth: false,\n linkedinOAuth: false,\n twitterOAuth: false,\n spotifyOAuth: false,\n} as const;\n\n// v3.1 integration defaults\nconst v31IntegrationDefaults = {\n paddle: false,\n lemonSqueezy: false,\n pagSeguro: false,\n asaas: false,\n anthropic: false,\n googleGemini: false,\n langchain: false,\n slackWebhook: false,\n discordWebhook: false,\n firebaseFcm: false,\n oneSignal: false,\n mapbox: false,\n hotjar: false,\n cloudinary: false,\n uploadThing: false,\n} as const;\n\n// v3.1 top-level defaults\nconst v31Defaults = {\n auth0: false,\n supabaseAuth: false,\n sendgrid: false,\n amazonSes: false,\n posthog: false,\n plausible: false,\n mixpanel: false,\n graphql: false,\n recaptcha: false,\n playwright: false,\n algolia: false,\n elasticsearch: false,\n typesense: false,\n inngest: false,\n puppeteer: false,\n strapi: false,\n sanity: false,\n supabase: false,\n firebase: false,\n neonDb: false,\n upstashRedis: false,\n flagsmith: false,\n launchDarkly: false,\n compression: false,\n} as const;\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, ...v3AuthDefaults, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: { viacep: false, whatsapp: false, stripe: true, mercadoPago: false, abacatePay: false, ...v3IntegrationDefaults, ...v31IntegrationDefaults },\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 ...v3Defaults,\n ...v31Defaults,\n sentry: true,\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, ...v3AuthDefaults, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: { viacep: false, whatsapp: false, stripe: true, mercadoPago: false, abacatePay: false, ...v3IntegrationDefaults, ...v31IntegrationDefaults },\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 ...v3Defaults,\n ...v31Defaults,\n sentry: true,\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, ...v3AuthDefaults, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: { viacep: true, whatsapp: true, stripe: true, mercadoPago: true, abacatePay: false, ...v3IntegrationDefaults, ...v31IntegrationDefaults },\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 ...v3Defaults,\n ...v31Defaults,\n meilisearch: true,\n pdfkit: true,\n googleAnalytics: true,\n cloudinary: true,\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, ...v3AuthDefaults, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'fastify',\n integrations: { viacep: false, whatsapp: false, stripe: false, mercadoPago: false, abacatePay: false, ...v3IntegrationDefaults, ...v31IntegrationDefaults },\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 ...v3Defaults,\n ...v31Defaults,\n sentry: true,\n vitest: true,\n compression: true,\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, ...v3AuthDefaults, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: { viacep: false, whatsapp: false, stripe: false, mercadoPago: false, abacatePay: false, ...v3IntegrationDefaults, ...v31IntegrationDefaults },\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 ...v3Defaults,\n ...v31Defaults,\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, ...v3AuthDefaults, ...v31AuthDefaults },\n queue: 'none',\n frontend: 'nextjs',\n backend: 'express',\n integrations: { viacep: false, whatsapp: false, stripe: false, mercadoPago: false, abacatePay: false, ...v3IntegrationDefaults, ...v31IntegrationDefaults },\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 ...v3Defaults,\n ...v31Defaults,\n healthChecks: false,\n },\n },\n\n // ═══════════════════════════════════════════\n // v3.0+ — New Presets\n // ═══════════════════════════════════════════\n\n 'ai-saas': {\n name: 'AI SaaS',\n description: 'SaaS com IA: OpenAI, Claude, Vercel AI SDK, Stripe, Clerk',\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: false, magicLink: false, googleOAuth: true, githubOAuth: true, appleSignIn: false, discordOAuth: false, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: {\n viacep: false, whatsapp: false, stripe: true, mercadoPago: false, abacatePay: false,\n paypal: false, openai: true, vercelAi: true, twilioSms: false, telegramBot: false, googleMaps: false,\n ...v31IntegrationDefaults, anthropic: true, langchain: true,\n },\n rbac: true,\n organizations: false,\n stripeBilling: true,\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 clerk: true,\n nextAuth: false,\n resend: true,\n awsS3: true,\n cloudflareR2: false,\n sentry: true,\n googleAnalytics: true,\n trpc: true,\n totp: false,\n vitest: true,\n meilisearch: false,\n nodeCron: false,\n pdfkit: false,\n healthChecks: true,\n ...v31Defaults,\n posthog: true,\n },\n },\n 'devtool': {\n name: 'DevTool',\n description: 'Ferramenta para devs: GitHub Auth, tRPC, Sentry, testes',\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, githubOAuth: true, appleSignIn: false, discordOAuth: true, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: {\n viacep: false, whatsapp: false, stripe: true, mercadoPago: false, abacatePay: false,\n paypal: false, openai: false, vercelAi: false, twilioSms: false, telegramBot: true, googleMaps: false,\n ...v31IntegrationDefaults, slackWebhook: true,\n },\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 clerk: false,\n nextAuth: false,\n resend: true,\n awsS3: false,\n cloudflareR2: false,\n sentry: true,\n googleAnalytics: false,\n trpc: true,\n totp: true,\n vitest: true,\n meilisearch: false,\n nodeCron: false,\n pdfkit: false,\n healthChecks: true,\n ...v31Defaults,\n playwright: true,\n flagsmith: true,\n },\n },\n 'brazil-saas': {\n name: 'Brazil SaaS',\n description: 'SaaS brasileiro: Mercado Pago, PagSeguro, ViaCEP, WhatsApp',\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: true, googleOAuth: true, githubOAuth: false, appleSignIn: false, discordOAuth: false, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: {\n viacep: true, whatsapp: true, stripe: false, mercadoPago: true, abacatePay: true,\n paypal: false, openai: false, vercelAi: false, twilioSms: false, telegramBot: false, googleMaps: false,\n ...v31IntegrationDefaults, pagSeguro: true, asaas: true,\n },\n rbac: true,\n organizations: true,\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: true,\n clerk: false,\n nextAuth: false,\n resend: true,\n awsS3: false,\n cloudflareR2: false,\n sentry: true,\n googleAnalytics: true,\n trpc: false,\n totp: false,\n vitest: false,\n meilisearch: false,\n nodeCron: true,\n pdfkit: true,\n healthChecks: true,\n ...v31Defaults,\n },\n },\n 'marketplace': {\n name: 'Marketplace',\n description: 'Marketplace com busca, storage, pagamentos e notificacoes',\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: false, googleOAuth: true, githubOAuth: false, appleSignIn: false, discordOAuth: false, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: {\n viacep: false, whatsapp: false, stripe: true, mercadoPago: false, abacatePay: false,\n paypal: true, openai: false, vercelAi: false, twilioSms: true, telegramBot: false, googleMaps: false,\n ...v31IntegrationDefaults, cloudinary: true,\n },\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: true,\n i18n: false,\n clerk: false,\n nextAuth: false,\n resend: false,\n awsS3: true,\n cloudflareR2: false,\n sentry: true,\n googleAnalytics: true,\n trpc: false,\n totp: false,\n vitest: false,\n meilisearch: true,\n nodeCron: true,\n pdfkit: true,\n healthChecks: true,\n ...v31Defaults,\n algolia: true,\n },\n },\n 'mobile-backend': {\n name: 'Mobile Backend',\n description: 'Backend para apps mobile: push, SMS, Apple Auth, 2FA, S3',\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: true, githubOAuth: false, appleSignIn: true, discordOAuth: false, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'fastify',\n integrations: {\n viacep: false, whatsapp: false, stripe: true, mercadoPago: false, abacatePay: false,\n paypal: false, openai: false, vercelAi: false, twilioSms: true, telegramBot: false, googleMaps: true,\n ...v31IntegrationDefaults, firebaseFcm: true, oneSignal: true,\n },\n rbac: true,\n organizations: false,\n stripeBilling: true,\n zod: true,\n rateLimiting: true,\n logging: true,\n swagger: true,\n tailwind: false,\n cicd: true,\n websockets: true,\n i18n: true,\n clerk: false,\n nextAuth: false,\n resend: true,\n awsS3: true,\n cloudflareR2: false,\n sentry: true,\n googleAnalytics: false,\n trpc: false,\n totp: true,\n vitest: true,\n meilisearch: false,\n nodeCron: true,\n pdfkit: false,\n healthChecks: true,\n ...v31Defaults,\n compression: true,\n },\n },\n 'content-platform': {\n name: 'Content Platform',\n description: 'Plataforma de conteudo com busca, CMS, analytics e storage',\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: true, googleOAuth: true, githubOAuth: false, appleSignIn: false, discordOAuth: false, ...v31AuthDefaults },\n queue: 'bullmq',\n frontend: 'nextjs',\n backend: 'nestjs',\n integrations: {\n viacep: false, whatsapp: false, stripe: true, mercadoPago: false, abacatePay: false,\n paypal: false, openai: true, vercelAi: true, twilioSms: false, telegramBot: false, googleMaps: false,\n ...v31IntegrationDefaults, cloudinary: true,\n },\n rbac: true,\n organizations: false,\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: true,\n clerk: false,\n nextAuth: false,\n resend: true,\n awsS3: false,\n cloudflareR2: true,\n sentry: true,\n googleAnalytics: true,\n trpc: false,\n totp: false,\n vitest: false,\n meilisearch: true,\n nodeCron: true,\n pdfkit: false,\n healthChecks: true,\n ...v31Defaults,\n sanity: true,\n posthog: true,\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 config.auth.githubOAuth && 'GitHub OAuth',\n config.auth.appleSignIn && 'Apple Sign-In',\n config.auth.discordOAuth && 'Discord OAuth',\n config.auth.facebookOAuth && 'Facebook OAuth',\n config.auth.microsoftOAuth && 'Microsoft OAuth',\n config.auth.linkedinOAuth && 'LinkedIn OAuth',\n config.auth.twitterOAuth && 'Twitter OAuth',\n config.auth.spotifyOAuth && 'Spotify 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 (config.clerk) {\n console.log(chalk.green(' + ') + chalk.white(`Clerk auth com UI pronto`));\n }\n if (config.nextAuth) {\n console.log(chalk.green(' + ') + chalk.white(`NextAuth/Auth.js configurado`));\n }\n if (config.resend) {\n console.log(chalk.green(' + ') + chalk.white(`Resend email service`));\n }\n if (config.awsS3) {\n console.log(chalk.green(' + ') + chalk.white(`AWS S3 storage`));\n }\n if (config.cloudflareR2) {\n console.log(chalk.green(' + ') + chalk.white(`Cloudflare R2 storage`));\n }\n if (config.sentry) {\n console.log(chalk.green(' + ') + chalk.white(`Sentry error tracking`));\n }\n if (config.googleAnalytics) {\n console.log(chalk.green(' + ') + chalk.white(`Google Analytics 4`));\n }\n if (config.trpc) {\n console.log(chalk.green(' + ') + chalk.white(`tRPC (API typesafe end-to-end)`));\n }\n if (config.totp) {\n console.log(chalk.green(' + ') + chalk.white(`2FA/TOTP com QR code`));\n }\n if (config.vitest) {\n console.log(chalk.green(' + ') + chalk.white(`Vitest + Supertest para testes`));\n }\n if (config.meilisearch) {\n console.log(chalk.green(' + ') + chalk.white(`Meilisearch busca full-text`));\n }\n if (config.nodeCron) {\n console.log(chalk.green(' + ') + chalk.white(`Cron jobs com node-cron`));\n }\n if (config.pdfkit) {\n console.log(chalk.green(' + ') + chalk.white(`PDFKit para gerar PDFs`));\n }\n if (config.healthChecks) {\n console.log(chalk.green(' + ') + chalk.white(`Health Checks em /api/health`));\n }\n // v3.1 features\n if (config.auth0) {\n console.log(chalk.green(' + ') + chalk.white(`Auth0 enterprise auth`));\n }\n if (config.supabaseAuth) {\n console.log(chalk.green(' + ') + chalk.white(`Supabase Auth`));\n }\n if (config.sendgrid) {\n console.log(chalk.green(' + ') + chalk.white(`SendGrid email`));\n }\n if (config.amazonSes) {\n console.log(chalk.green(' + ') + chalk.white(`Amazon SES email`));\n }\n if (config.posthog) {\n console.log(chalk.green(' + ') + chalk.white(`PostHog product analytics`));\n }\n if (config.plausible) {\n console.log(chalk.green(' + ') + chalk.white(`Plausible privacy-first analytics`));\n }\n if (config.mixpanel) {\n console.log(chalk.green(' + ') + chalk.white(`Mixpanel event analytics`));\n }\n if (config.graphql) {\n console.log(chalk.green(' + ') + chalk.white(`GraphQL (Apollo Server)`));\n }\n if (config.compression) {\n console.log(chalk.green(' + ') + chalk.white(`Compression (gzip/brotli)`));\n }\n if (config.recaptcha) {\n console.log(chalk.green(' + ') + chalk.white(`reCAPTCHA protecao contra bots`));\n }\n if (config.playwright) {\n console.log(chalk.green(' + ') + chalk.white(`Playwright E2E tests`));\n }\n if (config.algolia) {\n console.log(chalk.green(' + ') + chalk.white(`Algolia search`));\n }\n if (config.elasticsearch) {\n console.log(chalk.green(' + ') + chalk.white(`Elasticsearch`));\n }\n if (config.typesense) {\n console.log(chalk.green(' + ') + chalk.white(`Typesense search`));\n }\n if (config.inngest) {\n console.log(chalk.green(' + ') + chalk.white(`Inngest background jobs`));\n }\n if (config.puppeteer) {\n console.log(chalk.green(' + ') + chalk.white(`Puppeteer PDF/screenshots`));\n }\n if (config.strapi) {\n console.log(chalk.green(' + ') + chalk.white(`Strapi CMS integration`));\n }\n if (config.sanity) {\n console.log(chalk.green(' + ') + chalk.white(`Sanity CMS integration`));\n }\n if (config.supabase) {\n console.log(chalk.green(' + ') + chalk.white(`Supabase BaaS`));\n }\n if (config.firebase) {\n console.log(chalk.green(' + ') + chalk.white(`Firebase BaaS`));\n }\n if (config.neonDb) {\n console.log(chalk.green(' + ') + chalk.white(`Neon DB serverless`));\n }\n if (config.upstashRedis) {\n console.log(chalk.green(' + ') + chalk.white(`Upstash Redis serverless`));\n }\n if (config.flagsmith) {\n console.log(chalk.green(' + ') + chalk.white(`Flagsmith feature flags`));\n }\n if (config.launchDarkly) {\n console.log(chalk.green(' + ') + chalk.white(`LaunchDarkly feature flags`));\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\n // ---- NEW: v3.0 features ----\n\n // OAuth Providers\n 'passport-github2': '^0.1.12',\n '@types/passport-github2': '^1.2.9',\n '@fastify/oauth2': '^8.0.0',\n 'apple-signin-auth': '^1.7.6',\n 'passport-discord': '^0.1.4',\n\n // Auth Services\n '@clerk/nextjs': '^6.0.0',\n '@clerk/express': '^1.0.0',\n 'next-auth': '^5.0.0',\n '@auth/prisma-adapter': '^2.0.0',\n\n // Email - Resend\n 'resend': '^4.0.0',\n\n // Monitoring\n '@sentry/node': '^8.0.0',\n '@sentry/nextjs': '^8.0.0',\n\n // Analytics\n '@next/third-parties': '^15.0.0',\n\n // API Patterns\n '@trpc/server': '^11.0.0',\n '@trpc/client': '^11.0.0',\n '@trpc/next': '^11.0.0',\n '@trpc/react-query': '^11.0.0',\n '@tanstack/react-query': '^5.60.0',\n 'superjson': '^2.2.0',\n\n // Storage\n '@aws-sdk/client-s3': '^3.700.0',\n '@aws-sdk/s3-request-presigner': '^3.700.0',\n\n // Communication\n 'twilio': '^5.0.0',\n 'telegraf': '^4.16.0',\n\n // Security - 2FA/TOTP\n 'otplib': '^12.0.1',\n 'qrcode': '^1.5.4',\n '@types/qrcode': '^1.5.5',\n\n // Testing\n 'vitest': '^2.0.0',\n 'supertest': '^7.0.0',\n '@types/supertest': '^6.0.2',\n\n // Search\n 'meilisearch': '^0.44.0',\n\n // Scheduling\n 'node-cron': '^3.0.3',\n '@types/node-cron': '^3.0.11',\n\n // Payments\n '@paypal/checkout-server-sdk': '^1.0.3',\n\n // PDF\n 'pdfkit': '^0.15.0',\n '@types/pdfkit': '^0.13.5',\n\n // AI\n 'openai': '^4.70.0',\n 'ai': '^4.0.0',\n '@ai-sdk/openai': '^1.0.0',\n\n // Misc\n 'compression': '^1.7.4',\n '@types/compression': '^1.7.5',\n '@fastify/compress': '^8.0.0',\n '@nestjs/terminus': '^11.0.0',\n\n // ---- NEW: v3.1 features ----\n\n // More OAuth Providers\n 'passport-facebook': '^3.0.0',\n '@types/passport-facebook': '^3.0.3',\n 'passport-azure-ad': '^4.3.5',\n 'passport-linkedin-oauth2': '^2.0.0',\n 'passport-twitter': '^1.0.4',\n '@types/passport-twitter': '^1.0.40',\n 'passport-spotify': '^2.0.0',\n\n // More Auth Services\n 'auth0': '^4.0.0',\n 'express-openid-connect': '^2.17.0',\n '@supabase/supabase-js': '^2.45.0',\n\n // More Email\n '@sendgrid/mail': '^8.1.0',\n '@aws-sdk/client-ses': '^3.700.0',\n\n // More Payments\n '@paddle/paddle-node-sdk': '^1.0.0',\n '@lemonsqueezy/lemonsqueezy.js': '^3.0.0',\n\n // More AI\n '@anthropic-ai/sdk': '^0.30.0',\n '@google/generative-ai': '^0.21.0',\n 'langchain': '^0.3.0',\n '@langchain/openai': '^0.3.0',\n\n // More Communication\n '@slack/web-api': '^7.5.0',\n 'discord.js': '^14.16.0',\n 'firebase-admin': '^12.7.0',\n 'onesignal-node': '^3.4.0',\n\n // More Analytics\n 'posthog-node': '^4.2.0',\n 'mixpanel': '^0.18.0',\n\n // More Search\n 'algoliasearch': '^5.14.0',\n '@elastic/elasticsearch': '^8.16.0',\n 'typesense': '^1.8.0',\n\n // GraphQL\n '@apollo/server': '^4.11.0',\n 'graphql': '^16.9.0',\n '@nestjs/graphql': '^12.0.0',\n '@nestjs/apollo': '^12.0.0',\n\n // Security\n 'express-recaptcha': '^5.1.0',\n\n // More Testing\n '@playwright/test': '^1.48.0',\n\n // More PDF\n 'puppeteer': '^23.0.0',\n\n // Maps\n '@mapbox/mapbox-sdk': '^0.16.0',\n\n // More Scheduling\n 'inngest': '^3.27.0',\n\n // CMS\n '@sanity/client': '^6.22.0',\n\n // Storage\n 'uploadthing': '^7.0.0',\n 'cloudinary': '^2.5.0',\n\n // BaaS\n '@supabase/ssr': '^0.5.0',\n '@neon-ai/serverless': '^0.10.0',\n '@upstash/redis': '^1.34.0',\n\n // Feature Flags\n 'flagsmith-nodejs': '^4.0.0',\n 'launchdarkly-node-server-sdk': '^9.7.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 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 // v3.0 modules\n if (config.healthChecks) {\n imports.push(`import { HealthModule } from './health/health.module';`);\n modules.push('HealthModule');\n }\n\n if (config.nodeCron) {\n imports.push(`import { CronModule } from './jobs/cron.module';`);\n modules.push('CronModule');\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 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 githubOauthInstaller: 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: 'GITHUB_CLIENT_ID', value: '', category: 'GitHub OAuth', comment: 'Obtenha em https://github.com/settings/developers' },\n { key: 'GITHUB_CLIENT_SECRET', value: '', category: 'GitHub OAuth' },\n { key: 'GITHUB_CALLBACK_URL', value: 'http://localhost:3001/api/auth/github/callback', category: 'GitHub OAuth' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'github.strategy.ts'), `import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-github2';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class GitHubStrategy extends PassportStrategy(Strategy, 'github') {\n constructor(configService: ConfigService) {\n super({\n clientID: configService.get<string>('GITHUB_CLIENT_ID'),\n clientSecret: configService.get<string>('GITHUB_CLIENT_SECRET'),\n callbackURL: configService.get<string>('GITHUB_CALLBACK_URL'),\n scope: ['user:email'],\n });\n }\n\n async validate(\n accessToken: string,\n refreshToken: string,\n profile: any,\n done: (err: any, user?: any) => void,\n ) {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n githubId: 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', 'github.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/github')\nexport class GitHubController {\n @Get()\n @UseGuards(AuthGuard('github'))\n async githubAuth() {\n // Redireciona para o GitHub\n }\n\n @Get('callback')\n @UseGuards(AuthGuard('github'))\n async githubCallback(@Req() req: Request, @Res() res: Response) {\n const user = req.user;\n // TODO: Criar/buscar usuario no banco, gerar JWT\n console.log('GitHub 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', 'github.routes.ts'), `import { Router } from 'express';\nimport passport from 'passport';\nimport { Strategy as GitHubStrategy } from 'passport-github2';\n\npassport.use(\n new GitHubStrategy(\n {\n clientID: process.env.GITHUB_CLIENT_ID || '',\n clientSecret: process.env.GITHUB_CLIENT_SECRET || '',\n callbackURL: process.env.GITHUB_CALLBACK_URL || 'http://localhost:3001/api/auth/github/callback',\n },\n async (accessToken: string, refreshToken: string, profile: any, done: (err: any, user?: any) => void) => {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n githubId: 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 githubRouter = Router();\n\ngithubRouter.get('/', passport.authenticate('github', { scope: ['user:email'] }));\n\ngithubRouter.get(\n '/callback',\n passport.authenticate('github', { session: false }),\n (req, res) => {\n // TODO: Gerar JWT e redirecionar\n console.log('GitHub user:', req.user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n);\n\nexport { githubRouter };\n`);\n\n dependencies['passport'] = deps.passport;\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'github.routes.ts'), `import type { FastifyInstance } from 'fastify';\n\n// Para Fastify, recomendamos usar @fastify/oauth2\n// npm install @fastify/oauth2\nexport async function githubAuthRoutes(app: FastifyInstance) {\n // TODO: Configurar @fastify/oauth2 para GitHub\n // Documentacao: https://github.com/fastify/fastify-oauth2\n\n app.get('/api/auth/github', async (request, reply) => {\n const clientId = process.env.GITHUB_CLIENT_ID;\n const redirectUri = process.env.GITHUB_CALLBACK_URL;\n const url = \\`https://github.com/login/oauth/authorize?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&scope=user:email\\`;\n reply.redirect(url);\n });\n\n app.get('/api/auth/github/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: 'GitHub OAuth callback', code };\n });\n}\n`);\n }\n\n dependencies['passport-github2'] = deps['passport-github2'];\n devDependencies['@types/passport-github2'] = deps['@types/passport-github2'];\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 appleSignInInstaller: 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: 'APPLE_CLIENT_ID', value: '', category: 'Apple Sign In', comment: 'Obtenha em https://developer.apple.com' },\n { key: 'APPLE_TEAM_ID', value: '', category: 'Apple Sign In' },\n { key: 'APPLE_KEY_ID', value: '', category: 'Apple Sign In' },\n { key: 'APPLE_PRIVATE_KEY', value: '', category: 'Apple Sign In' },\n { key: 'APPLE_CALLBACK_URL', value: 'http://localhost:3001/api/auth/apple/callback', category: 'Apple Sign In' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'apple.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport appleSignIn from 'apple-signin-auth';\n\n@Injectable()\nexport class AppleAuthService {\n constructor(private configService: ConfigService) {}\n\n async verifyIdToken(idToken: string) {\n try {\n const payload = await appleSignIn.verifyIdToken(idToken, {\n audience: this.configService.get<string>('APPLE_CLIENT_ID'),\n ignoreExpiration: false,\n });\n\n return {\n appleId: payload.sub,\n email: payload.email,\n emailVerified: payload.email_verified === 'true',\n };\n } catch (error) {\n throw new Error('Token Apple invalido: ' + (error as Error).message);\n }\n }\n\n getAuthorizationUrl() {\n const clientId = this.configService.get<string>('APPLE_CLIENT_ID');\n const redirectUri = this.configService.get<string>('APPLE_CALLBACK_URL');\n const url = \\`https://appleid.apple.com/auth/authorize?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&response_type=code id_token&scope=name email&response_mode=form_post\\`;\n return url;\n }\n}\n`);\n } else if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'apple.service.ts'), `import appleSignIn from 'apple-signin-auth';\n\nexport async function verifyIdToken(idToken: string) {\n try {\n const payload = await appleSignIn.verifyIdToken(idToken, {\n audience: process.env.APPLE_CLIENT_ID || '',\n ignoreExpiration: false,\n });\n\n return {\n appleId: payload.sub,\n email: payload.email,\n emailVerified: payload.email_verified === 'true',\n };\n } catch (error) {\n throw new Error('Token Apple invalido: ' + (error as Error).message);\n }\n}\n\nexport function getAuthorizationUrl() {\n const clientId = process.env.APPLE_CLIENT_ID;\n const redirectUri = process.env.APPLE_CALLBACK_URL;\n const url = \\`https://appleid.apple.com/auth/authorize?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&response_type=code id_token&scope=name email&response_mode=form_post\\`;\n return url;\n}\n`);\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'apple.service.ts'), `import appleSignIn from 'apple-signin-auth';\n\nexport async function verifyIdToken(idToken: string) {\n try {\n const payload = await appleSignIn.verifyIdToken(idToken, {\n audience: process.env.APPLE_CLIENT_ID || '',\n ignoreExpiration: false,\n });\n\n return {\n appleId: payload.sub,\n email: payload.email,\n emailVerified: payload.email_verified === 'true',\n };\n } catch (error) {\n throw new Error('Token Apple invalido: ' + (error as Error).message);\n }\n}\n\nexport function getAuthorizationUrl() {\n const clientId = process.env.APPLE_CLIENT_ID;\n const redirectUri = process.env.APPLE_CALLBACK_URL;\n const url = \\`https://appleid.apple.com/auth/authorize?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&response_type=code id_token&scope=name email&response_mode=form_post\\`;\n return url;\n}\n`);\n }\n\n dependencies['apple-signin-auth'] = deps['apple-signin-auth'];\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 discordOauthInstaller: 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: 'DISCORD_CLIENT_ID', value: '', category: 'Discord OAuth', comment: 'Obtenha em https://discord.com/developers/applications' },\n { key: 'DISCORD_CLIENT_SECRET', value: '', category: 'Discord OAuth' },\n { key: 'DISCORD_CALLBACK_URL', value: 'http://localhost:3001/api/auth/discord/callback', category: 'Discord OAuth' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'discord.strategy.ts'), `import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-discord';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class DiscordStrategy extends PassportStrategy(Strategy, 'discord') {\n constructor(configService: ConfigService) {\n super({\n clientID: configService.get<string>('DISCORD_CLIENT_ID'),\n clientSecret: configService.get<string>('DISCORD_CLIENT_SECRET'),\n callbackURL: configService.get<string>('DISCORD_CALLBACK_URL'),\n scope: ['identify', 'email'],\n });\n }\n\n async validate(\n accessToken: string,\n refreshToken: string,\n profile: any,\n done: (err: any, user?: any) => void,\n ) {\n const user = {\n email: profile.email,\n name: profile.username,\n discordId: profile.id,\n avatar: profile.avatar ? \\`https://cdn.discordapp.com/avatars/\\${profile.id}/\\${profile.avatar}.png\\` : null,\n };\n done(null, user);\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'discord.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/discord')\nexport class DiscordController {\n @Get()\n @UseGuards(AuthGuard('discord'))\n async discordAuth() {\n // Redireciona para o Discord\n }\n\n @Get('callback')\n @UseGuards(AuthGuard('discord'))\n async discordCallback(@Req() req: Request, @Res() res: Response) {\n const user = req.user;\n // TODO: Criar/buscar usuario no banco, gerar JWT\n console.log('Discord 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', 'discord.routes.ts'), `import { Router } from 'express';\nimport passport from 'passport';\nimport { Strategy as DiscordStrategy } from 'passport-discord';\n\npassport.use(\n new DiscordStrategy(\n {\n clientID: process.env.DISCORD_CLIENT_ID || '',\n clientSecret: process.env.DISCORD_CLIENT_SECRET || '',\n callbackURL: process.env.DISCORD_CALLBACK_URL || 'http://localhost:3001/api/auth/discord/callback',\n },\n async (accessToken: string, refreshToken: string, profile: any, done: (err: any, user?: any) => void) => {\n const user = {\n email: profile.email,\n name: profile.username,\n discordId: profile.id,\n avatar: profile.avatar ? \\`https://cdn.discordapp.com/avatars/\\${profile.id}/\\${profile.avatar}.png\\` : null,\n };\n // TODO: Criar/buscar usuario no banco\n done(null, user);\n }\n )\n);\n\nconst discordRouter = Router();\n\ndiscordRouter.get('/', passport.authenticate('discord', { scope: ['identify', 'email'] }));\n\ndiscordRouter.get(\n '/callback',\n passport.authenticate('discord', { session: false }),\n (req, res) => {\n // TODO: Gerar JWT e redirecionar\n console.log('Discord user:', req.user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n);\n\nexport { discordRouter };\n`);\n\n dependencies['passport'] = deps.passport;\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'discord.routes.ts'), `import type { FastifyInstance } from 'fastify';\n\n// Para Fastify, recomendamos usar @fastify/oauth2\n// npm install @fastify/oauth2\nexport async function discordAuthRoutes(app: FastifyInstance) {\n // TODO: Configurar @fastify/oauth2 para Discord\n // Documentacao: https://github.com/fastify/fastify-oauth2\n\n app.get('/api/auth/discord', async (request, reply) => {\n const clientId = process.env.DISCORD_CLIENT_ID;\n const redirectUri = process.env.DISCORD_CALLBACK_URL;\n const url = \\`https://discord.com/api/oauth2/authorize?client_id=\\${clientId}&redirect_uri=\\${encodeURIComponent(redirectUri || '')}&response_type=code&scope=identify email\\`;\n reply.redirect(url);\n });\n\n app.get('/api/auth/discord/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: 'Discord OAuth callback', code };\n });\n}\n`);\n }\n\n dependencies['passport-discord'] = deps['passport-discord'];\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 clerkInstaller: 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: 'CLERK_SECRET_KEY', value: '', category: 'Clerk', comment: 'Obtenha em https://dashboard.clerk.com' },\n { key: 'NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY', value: '', category: 'Clerk' },\n { key: 'CLERK_WEBHOOK_SECRET', value: '', category: 'Clerk' },\n );\n\n if (config.backend === 'nestjs') {\n // ── NestJS: Guard que valida session tokens do Clerk ──\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'clerk.guard.ts'), `import {\n CanActivate,\n ExecutionContext,\n Injectable,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { createClerkClient } from '@clerk/express';\n\nconst clerkClient = createClerkClient({\n secretKey: process.env.CLERK_SECRET_KEY,\n});\n\n/**\n * Guard NestJS que valida session tokens do Clerk.\n *\n * Uso:\n * @UseGuards(ClerkAuthGuard)\n * @Get('profile')\n * getProfile(@Req() req: Request) {\n * const userId = (req as any).auth.userId;\n * }\n */\n@Injectable()\nexport class ClerkAuthGuard implements CanActivate {\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest();\n const authHeader = request.headers.authorization;\n\n if (!authHeader?.startsWith('Bearer ')) {\n throw new UnauthorizedException('Token não fornecido');\n }\n\n const token = authHeader.split(' ')[1];\n\n try {\n const payload = await clerkClient.verifyToken(token);\n request.auth = {\n userId: payload.sub,\n sessionId: payload.sid,\n claims: payload,\n };\n return true;\n } catch {\n throw new UnauthorizedException('Token Clerk inválido');\n }\n }\n}\n`);\n\n } else if (config.backend === 'express') {\n // ── Express: Middleware usando @clerk/express ──\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'clerk.middleware.ts'), `import { clerkMiddleware, requireAuth, getAuth } from '@clerk/express';\nimport type { Request, Response, NextFunction } from 'express';\n\n/**\n * Middleware do Clerk para Express.\n *\n * Uso no app principal:\n * import { clerkAuth, requireClerkAuth } from './auth/clerk.middleware.js';\n *\n * // Adicionar em todas as rotas (popula req.auth se houver sessão)\n * app.use(clerkAuth);\n *\n * // Proteger rotas específicas\n * app.get('/api/profile', requireClerkAuth, (req, res) => {\n * const { userId } = getAuth(req);\n * res.json({ userId });\n * });\n */\n\nexport const clerkAuth = clerkMiddleware();\n\nexport const requireClerkAuth = requireAuth();\n\nexport { getAuth };\n`);\n\n } else {\n // ── Fastify: Verificação manual de token via Clerk SDK ──\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'clerk.middleware.ts'), `import type { FastifyRequest, FastifyReply } from 'fastify';\nimport { createClerkClient } from '@clerk/express';\n\nconst clerkClient = createClerkClient({\n secretKey: process.env.CLERK_SECRET_KEY,\n});\n\n/**\n * Hook Fastify para validar session tokens do Clerk.\n *\n * Uso:\n * app.addHook('preHandler', clerkAuthHook);\n *\n * // Ou em rotas específicas:\n * app.get('/api/profile', { preHandler: clerkAuthHook }, async (request) => {\n * const userId = (request as any).auth.userId;\n * return { userId };\n * });\n */\nexport async function clerkAuthHook(request: FastifyRequest, reply: FastifyReply) {\n const authHeader = request.headers.authorization;\n\n if (!authHeader?.startsWith('Bearer ')) {\n return reply.status(401).send({ error: 'Token não fornecido' });\n }\n\n const token = authHeader.split(' ')[1];\n\n try {\n const payload = await clerkClient.verifyToken(token);\n (request as any).auth = {\n userId: payload.sub,\n sessionId: payload.sid,\n claims: payload,\n };\n } catch {\n return reply.status(401).send({ error: 'Token Clerk inválido' });\n }\n}\n`);\n }\n\n dependencies['@clerk/express'] = deps['@clerk/express'];\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 nextAuthInstaller: 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: 'NEXTAUTH_SECRET', value: 'change-me-in-production', category: 'NextAuth' },\n { key: 'NEXTAUTH_URL', value: 'http://localhost:3000', category: 'NextAuth' },\n );\n\n // ── Configuração NextAuth para todos os backends ──\n\n const prismaImports = config.usePrisma\n ? `import { PrismaAdapter } from '@auth/prisma-adapter';\nimport { PrismaClient } from '@prisma/client';\n\nconst prisma = new PrismaClient();\n`\n : '';\n\n const adapterConfig = config.usePrisma\n ? ` adapter: PrismaAdapter(prisma),`\n : '';\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth.config.ts'), `${prismaImports}import NextAuth from 'next-auth';\nimport CredentialsProvider from 'next-auth/providers/credentials';\n\n/**\n * Configuração do NextAuth.\n *\n * Para adicionar novos providers (Google, GitHub, etc.), consulte:\n * https://authjs.dev/getting-started/providers\n *\n * Se estiver usando Prisma, o adapter já está configurado para\n * persistir sessões e contas no banco de dados.\n */\nexport const authOptions = {\n${adapterConfig}\n providers: [\n CredentialsProvider({\n name: 'Credentials',\n credentials: {\n email: { label: 'Email', type: 'email', placeholder: 'email@exemplo.com' },\n password: { label: 'Senha', type: 'password' },\n },\n async authorize(credentials) {\n if (!credentials?.email || !credentials?.password) {\n return null;\n }\n\n // TODO: Buscar usuario no banco e validar senha\n // Exemplo com Prisma:\n // const user = await prisma.user.findUnique({\n // where: { email: credentials.email },\n // });\n // if (!user || !await bcrypt.compare(credentials.password, user.password)) {\n // return null;\n // }\n // return { id: user.id, email: user.email, name: user.name };\n\n // Placeholder - remova e implemente a lógica real\n return {\n id: '1',\n email: credentials.email,\n name: 'Usuário Exemplo',\n };\n },\n }),\n ],\n session: {\n strategy: 'jwt' as const,\n },\n pages: {\n signIn: '/auth/signin',\n // signOut: '/auth/signout',\n // error: '/auth/error',\n },\n callbacks: {\n async jwt({ token, user }: { token: any; user: any }) {\n if (user) {\n token.id = user.id;\n }\n return token;\n },\n async session({ session, token }: { session: any; token: any }) {\n if (session.user) {\n session.user.id = token.id;\n }\n return session;\n },\n },\n secret: process.env.NEXTAUTH_SECRET,\n};\n\nexport const { handlers, auth, signIn, signOut } = NextAuth(authOptions);\n`);\n\n dependencies['next-auth'] = deps['next-auth'];\n\n if (config.usePrisma) {\n dependencies['@auth/prisma-adapter'] = deps['@auth/prisma-adapter'];\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 totpInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'auth', 'totp'));\n\n if (config.backend === 'nestjs') {\n // ── NestJS: Injectable TotpService ──\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'totp', 'totp.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { authenticator } from 'otplib';\nimport * as QRCode from 'qrcode';\n\n/**\n * Serviço de autenticação TOTP (Time-based One-Time Password).\n *\n * Fluxo de uso:\n * 1. Gere um secret para o usuario com generateSecret()\n * 2. Salve o secret no banco de dados (associado ao usuario)\n * 3. Gere o QR Code com generateQRCode() para o usuario escanear no app (Google Authenticator, Authy, etc.)\n * 4. Valide os tokens com verifyToken() durante o login\n */\n@Injectable()\nexport class TotpService {\n /**\n * Gera um novo secret TOTP para um usuario.\n * Armazene este secret de forma segura no banco de dados.\n */\n generateSecret(): string {\n return authenticator.generateSecret();\n }\n\n /**\n * Gera um QR Code em formato data URL para o usuario escanear.\n * @param email - Email ou identificador do usuario\n * @param secret - Secret TOTP gerado por generateSecret()\n * @param issuer - Nome da aplicação exibido no app autenticador\n */\n async generateQRCode(email: string, secret: string, issuer = 'MyApp'): Promise<string> {\n const otpauth = authenticator.keyuri(email, issuer, secret);\n return QRCode.toDataURL(otpauth);\n }\n\n /**\n * Verifica se o token TOTP fornecido pelo usuario é válido.\n * @param token - Código de 6 dígitos fornecido pelo usuario\n * @param secret - Secret TOTP armazenado no banco de dados\n */\n verifyToken(token: string, secret: string): boolean {\n return authenticator.verify({ token, secret });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'totp', 'totp.module.ts'), `import { Module } from '@nestjs/common';\nimport { TotpService } from './totp.service';\n\n@Module({\n providers: [TotpService],\n exports: [TotpService],\n})\nexport class TotpModule {}\n`);\n\n } else {\n // ── Express / Fastify: Funções utilitárias ──\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'totp', 'totp.ts'), `import { authenticator } from 'otplib';\nimport * as QRCode from 'qrcode';\n\n/**\n * Utilitários de autenticação TOTP (Time-based One-Time Password).\n *\n * Fluxo de uso:\n * 1. Gere um secret para o usuario com generateSecret()\n * 2. Salve o secret no banco de dados (associado ao usuario)\n * 3. Gere o QR Code com generateQRCode() para o usuario escanear no app (Google Authenticator, Authy, etc.)\n * 4. Valide os tokens com verifyToken() durante o login\n */\n\n/**\n * Gera um novo secret TOTP para um usuario.\n * Armazene este secret de forma segura no banco de dados.\n */\nexport function generateSecret(): string {\n return authenticator.generateSecret();\n}\n\n/**\n * Gera um QR Code em formato data URL para o usuario escanear.\n * @param email - Email ou identificador do usuario\n * @param secret - Secret TOTP gerado por generateSecret()\n * @param issuer - Nome da aplicação exibido no app autenticador\n */\nexport async function generateQRCode(\n email: string,\n secret: string,\n issuer = 'MyApp',\n): Promise<string> {\n const otpauth = authenticator.keyuri(email, issuer, secret);\n return QRCode.toDataURL(otpauth);\n}\n\n/**\n * Verifica se o token TOTP fornecido pelo usuario é válido.\n * @param token - Código de 6 dígitos fornecido pelo usuario\n * @param secret - Secret TOTP armazenado no banco de dados\n */\nexport function verifyToken(token: string, secret: string): boolean {\n return authenticator.verify({ token, secret });\n}\n`);\n }\n\n dependencies['otplib'] = deps.otplib;\n dependencies['qrcode'] = deps.qrcode;\n devDependencies['@types/qrcode'] = deps['@types/qrcode'];\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 sentryInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n const sentryDir = path.join(apiDir, 'src', 'infra', 'sentry');\n await ensureDir(sentryDir);\n\n envEntries.push(\n { key: 'SENTRY_DSN', value: '', category: 'Sentry', comment: 'Obtenha em https://sentry.io' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(sentryDir, 'sentry.interceptor.ts'), `import {\n Injectable,\n NestInterceptor,\n ExecutionContext,\n CallHandler,\n} from '@nestjs/common';\nimport { Observable, tap } from 'rxjs';\nimport * as Sentry from '@sentry/node';\n\n@Injectable()\nexport class SentryInterceptor implements NestInterceptor {\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n return next.handle().pipe(\n tap({\n error: (exception) => {\n Sentry.captureException(exception);\n },\n }),\n );\n }\n}\n`);\n\n await writeFile(path.join(sentryDir, 'sentry.module.ts'), `import { Global, Module, OnModuleInit } from '@nestjs/common';\nimport { APP_INTERCEPTOR } from '@nestjs/core';\nimport { ConfigService } from '@nestjs/config';\nimport * as Sentry from '@sentry/node';\nimport { SentryInterceptor } from './sentry.interceptor';\n\n@Global()\n@Module({\n providers: [\n {\n provide: APP_INTERCEPTOR,\n useClass: SentryInterceptor,\n },\n ],\n})\nexport class SentryModule implements OnModuleInit {\n constructor(private configService: ConfigService) {}\n\n onModuleInit() {\n const dsn = this.configService.get<string>('SENTRY_DSN');\n\n if (dsn) {\n Sentry.init({\n dsn,\n environment: this.configService.get('NODE_ENV', 'development'),\n tracesSampleRate: 1.0,\n });\n console.log('Sentry inicializado');\n }\n }\n}\n`);\n } else if (config.backend === 'express') {\n await writeFile(path.join(sentryDir, 'sentry.ts'), `import * as Sentry from '@sentry/node';\nimport type { Request, Response, NextFunction } from 'express';\n\n/**\n * Inicializa o Sentry. Chame esta funcao antes de registrar rotas.\n */\nexport function initSentry(): void {\n const dsn = process.env.SENTRY_DSN;\n\n if (dsn) {\n Sentry.init({\n dsn,\n environment: process.env.NODE_ENV || 'development',\n tracesSampleRate: 1.0,\n });\n console.log('Sentry inicializado');\n }\n}\n\n/**\n * Middleware de erro para Express.\n * Registre como o ultimo middleware de erro:\n *\n * app.use(sentryErrorHandler);\n */\nexport function sentryErrorHandler(err: Error, _req: Request, _res: Response, next: NextFunction): void {\n Sentry.captureException(err);\n next(err);\n}\n\nexport default { initSentry, sentryErrorHandler };\n`);\n } else {\n await writeFile(path.join(sentryDir, 'sentry.ts'), `import * as Sentry from '@sentry/node';\nimport type { FastifyInstance } from 'fastify';\n\n/**\n * Plugin Fastify para captura de erros com Sentry.\n *\n * Uso:\n * import { sentryPlugin } from './infra/sentry/sentry.js';\n * app.register(sentryPlugin);\n */\nexport async function sentryPlugin(app: FastifyInstance): Promise<void> {\n const dsn = process.env.SENTRY_DSN;\n\n if (dsn) {\n Sentry.init({\n dsn,\n environment: process.env.NODE_ENV || 'development',\n tracesSampleRate: 1.0,\n });\n console.log('Sentry inicializado');\n }\n\n app.addHook('onError', (_request, _reply, error, done) => {\n Sentry.captureException(error);\n done();\n });\n}\n\nexport default sentryPlugin;\n`);\n }\n\n dependencies['@sentry/node'] = deps['@sentry/node'];\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 resendInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'email'));\n\n envEntries.push(\n { key: 'RESEND_API_KEY', value: '', category: 'Resend', comment: 'Obtenha em https://resend.com' },\n { key: 'EMAIL_FROM', value: 'noreply@example.com', category: 'Resend' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'resend.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { Resend } from 'resend';\n\n@Injectable()\nexport class ResendService {\n private resend: Resend;\n\n constructor(private configService: ConfigService) {\n this.resend = new Resend(this.configService.get('RESEND_API_KEY', ''));\n }\n\n async send(params: {\n to: string | string[];\n subject: string;\n html: string;\n }): Promise<void> {\n await this.resend.emails.send({\n from: this.configService.get('EMAIL_FROM', 'noreply@example.com'),\n to: params.to,\n subject: params.subject,\n html: params.html,\n });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'resend.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { ResendService } from './resend.service';\n\n@Global()\n@Module({\n providers: [ResendService],\n exports: [ResendService],\n})\nexport class ResendModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'resend.ts'), `import { Resend } from 'resend';\n\nconst resend = new Resend(process.env.RESEND_API_KEY || '');\n\nexport async function sendEmail(params: {\n to: string | string[];\n subject: string;\n html: string;\n}): Promise<void> {\n await resend.emails.send({\n from: process.env.EMAIL_FROM || 'noreply@example.com',\n to: params.to,\n subject: params.subject,\n html: params.html,\n });\n}\n\nexport default { sendEmail };\n`);\n }\n\n dependencies['resend'] = deps.resend;\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 awsS3Installer: 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: 'AWS_ACCESS_KEY_ID', value: '', category: 'AWS S3' },\n { key: 'AWS_SECRET_ACCESS_KEY', value: '', category: 'AWS S3' },\n { key: 'AWS_REGION', value: 'us-east-1', category: 'AWS S3' },\n { key: 'AWS_S3_BUCKET', value: '', category: 'AWS S3' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 's3.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport {\n S3Client,\n PutObjectCommand,\n GetObjectCommand,\n DeleteObjectCommand,\n} from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\n\n@Injectable()\nexport class S3Service {\n private client: S3Client;\n private bucket: string;\n\n constructor(private configService: ConfigService) {\n this.bucket = this.configService.get('AWS_S3_BUCKET', '');\n this.client = new S3Client({\n region: this.configService.get('AWS_REGION', 'us-east-1'),\n credentials: {\n accessKeyId: this.configService.get('AWS_ACCESS_KEY_ID', ''),\n secretAccessKey: this.configService.get('AWS_SECRET_ACCESS_KEY', ''),\n },\n });\n }\n\n async upload(key: string, body: Buffer, contentType?: string): Promise<string> {\n await this.client.send(\n new PutObjectCommand({\n Bucket: this.bucket,\n Key: key,\n Body: body,\n ContentType: contentType || 'application/octet-stream',\n }),\n );\n return key;\n }\n\n async download(key: string): Promise<Buffer> {\n const response = await this.client.send(\n new GetObjectCommand({\n Bucket: this.bucket,\n Key: key,\n }),\n );\n const stream = response.Body as NodeJS.ReadableStream;\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.from(chunk));\n }\n return Buffer.concat(chunks);\n }\n\n async getSignedUrl(key: string, expiresIn = 3600): Promise<string> {\n const command = new GetObjectCommand({\n Bucket: this.bucket,\n Key: key,\n });\n return getSignedUrl(this.client, command, { expiresIn });\n }\n\n async delete(key: string): Promise<void> {\n await this.client.send(\n new DeleteObjectCommand({\n Bucket: this.bucket,\n Key: key,\n }),\n );\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 's3.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { S3Service } from './s3.service';\n\n@Global()\n@Module({\n providers: [S3Service],\n exports: [S3Service],\n})\nexport class S3Module {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 's3.ts'), `import {\n S3Client,\n PutObjectCommand,\n GetObjectCommand,\n DeleteObjectCommand,\n} from '@aws-sdk/client-s3';\nimport { getSignedUrl as presign } from '@aws-sdk/s3-request-presigner';\n\nconst BUCKET = process.env.AWS_S3_BUCKET || '';\n\nconst s3Client = new S3Client({\n region: process.env.AWS_REGION || 'us-east-1',\n credentials: {\n accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || '',\n },\n});\n\nexport async function upload(key: string, body: Buffer, contentType?: string): Promise<string> {\n await s3Client.send(\n new PutObjectCommand({\n Bucket: BUCKET,\n Key: key,\n Body: body,\n ContentType: contentType || 'application/octet-stream',\n }),\n );\n return key;\n}\n\nexport async function download(key: string): Promise<Buffer> {\n const response = await s3Client.send(\n new GetObjectCommand({\n Bucket: BUCKET,\n Key: key,\n }),\n );\n const stream = response.Body as NodeJS.ReadableStream;\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.from(chunk));\n }\n return Buffer.concat(chunks);\n}\n\nexport async function getSignedUrl(key: string, expiresIn = 3600): Promise<string> {\n const command = new GetObjectCommand({\n Bucket: BUCKET,\n Key: key,\n });\n return presign(s3Client, command, { expiresIn });\n}\n\nexport async function deleteFile(key: string): Promise<void> {\n await s3Client.send(\n new DeleteObjectCommand({\n Bucket: BUCKET,\n Key: key,\n }),\n );\n}\n\nexport default { upload, download, getSignedUrl, deleteFile };\n`);\n }\n\n dependencies['@aws-sdk/client-s3'] = deps['@aws-sdk/client-s3'];\n dependencies['@aws-sdk/s3-request-presigner'] = deps['@aws-sdk/s3-request-presigner'];\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 cloudflareR2Installer: 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: 'R2_ACCESS_KEY_ID', value: '', category: 'Cloudflare R2' },\n { key: 'R2_SECRET_ACCESS_KEY', value: '', category: 'Cloudflare R2' },\n { key: 'R2_ENDPOINT', value: '', category: 'Cloudflare R2', comment: 'https://<account-id>.r2.cloudflarestorage.com' },\n { key: 'R2_BUCKET', value: '', category: 'Cloudflare R2' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'r2.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport {\n S3Client,\n PutObjectCommand,\n GetObjectCommand,\n DeleteObjectCommand,\n} from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\n\n@Injectable()\nexport class R2Service {\n private client: S3Client;\n private bucket: string;\n\n constructor(private configService: ConfigService) {\n this.bucket = this.configService.get('R2_BUCKET', '');\n this.client = new S3Client({\n region: 'auto',\n endpoint: this.configService.get('R2_ENDPOINT', ''),\n credentials: {\n accessKeyId: this.configService.get('R2_ACCESS_KEY_ID', ''),\n secretAccessKey: this.configService.get('R2_SECRET_ACCESS_KEY', ''),\n },\n });\n }\n\n async upload(key: string, body: Buffer, contentType?: string): Promise<string> {\n await this.client.send(\n new PutObjectCommand({\n Bucket: this.bucket,\n Key: key,\n Body: body,\n ContentType: contentType || 'application/octet-stream',\n }),\n );\n return key;\n }\n\n async download(key: string): Promise<Buffer> {\n const response = await this.client.send(\n new GetObjectCommand({\n Bucket: this.bucket,\n Key: key,\n }),\n );\n const stream = response.Body as NodeJS.ReadableStream;\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.from(chunk));\n }\n return Buffer.concat(chunks);\n }\n\n async getSignedUrl(key: string, expiresIn = 3600): Promise<string> {\n const command = new GetObjectCommand({\n Bucket: this.bucket,\n Key: key,\n });\n return getSignedUrl(this.client, command, { expiresIn });\n }\n\n async delete(key: string): Promise<void> {\n await this.client.send(\n new DeleteObjectCommand({\n Bucket: this.bucket,\n Key: key,\n }),\n );\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'r2.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { R2Service } from './r2.service';\n\n@Global()\n@Module({\n providers: [R2Service],\n exports: [R2Service],\n})\nexport class R2Module {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'r2.ts'), `import {\n S3Client,\n PutObjectCommand,\n GetObjectCommand,\n DeleteObjectCommand,\n} from '@aws-sdk/client-s3';\nimport { getSignedUrl as presign } from '@aws-sdk/s3-request-presigner';\n\nconst BUCKET = process.env.R2_BUCKET || '';\n\nconst r2Client = new S3Client({\n region: 'auto',\n endpoint: process.env.R2_ENDPOINT || '',\n credentials: {\n accessKeyId: process.env.R2_ACCESS_KEY_ID || '',\n secretAccessKey: process.env.R2_SECRET_ACCESS_KEY || '',\n },\n});\n\nexport async function upload(key: string, body: Buffer, contentType?: string): Promise<string> {\n await r2Client.send(\n new PutObjectCommand({\n Bucket: BUCKET,\n Key: key,\n Body: body,\n ContentType: contentType || 'application/octet-stream',\n }),\n );\n return key;\n}\n\nexport async function download(key: string): Promise<Buffer> {\n const response = await r2Client.send(\n new GetObjectCommand({\n Bucket: BUCKET,\n Key: key,\n }),\n );\n const stream = response.Body as NodeJS.ReadableStream;\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.from(chunk));\n }\n return Buffer.concat(chunks);\n}\n\nexport async function getSignedUrl(key: string, expiresIn = 3600): Promise<string> {\n const command = new GetObjectCommand({\n Bucket: BUCKET,\n Key: key,\n });\n return presign(r2Client, command, { expiresIn });\n}\n\nexport async function deleteFile(key: string): Promise<void> {\n await r2Client.send(\n new DeleteObjectCommand({\n Bucket: BUCKET,\n Key: key,\n }),\n );\n}\n\nexport default { upload, download, getSignedUrl, deleteFile };\n`);\n }\n\n dependencies['@aws-sdk/client-s3'] = deps['@aws-sdk/client-s3'];\n dependencies['@aws-sdk/s3-request-presigner'] = deps['@aws-sdk/s3-request-presigner'];\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 trpcInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'trpc'));\n\n if (config.backend === 'nestjs') {\n // ── NestJS: tRPC router, context, and module ──\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'trpc.ts'), `import { initTRPC } from '@trpc/server';\nimport superjson from 'superjson';\n\n/**\n * Context criado para cada request tRPC.\n * Adicione dados como usuario autenticado, prisma client, etc.\n */\nexport interface Context {\n // TODO: Adicione propriedades de contexto (ex: user, prisma)\n}\n\nexport function createContext(): Context {\n return {};\n}\n\nconst t = initTRPC.context<Context>().create({\n transformer: superjson,\n});\n\nexport const router = t.router;\nexport const publicProcedure = t.procedure;\nexport const middleware = t.middleware;\n`);\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'trpc.router.ts'), `import { z } from 'zod';\nimport { router, publicProcedure } from './trpc.js';\n\nexport const appRouter = router({\n hello: publicProcedure\n .input(z.object({ name: z.string().optional() }))\n .query(({ input }) => {\n return {\n greeting: \\`Olá \\${input.name ?? 'mundo'}!\\`,\n };\n }),\n\n getUser: publicProcedure\n .input(z.object({ id: z.string() }))\n .query(({ input }) => {\n // TODO: Buscar usuario no banco de dados\n return {\n id: input.id,\n name: 'Usuário Exemplo',\n email: 'usuario@exemplo.com',\n };\n }),\n});\n\nexport type AppRouter = typeof appRouter;\n`);\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'trpc.module.ts'), `import { Module } from '@nestjs/common';\nimport { TRPCController } from './trpc.controller';\n\n/**\n * Módulo NestJS que expõe as rotas tRPC via /trpc.\n * Importe este módulo no AppModule para habilitar tRPC.\n */\n@Module({\n controllers: [TRPCController],\n})\nexport class TRPCModule {}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'trpc.controller.ts'), `import { All, Controller, Req, Res } from '@nestjs/common';\nimport { fetchRequestHandler } from '@trpc/server/adapters/fetch';\nimport type { Request, Response } from 'express';\nimport { appRouter } from './trpc.router.js';\nimport { createContext } from './trpc.js';\n\n@Controller('trpc')\nexport class TRPCController {\n @All('*')\n async handler(@Req() req: Request, @Res() res: Response) {\n const url = new URL(req.url, \\`http://\\${req.headers.host}\\`);\n\n const response = await fetchRequestHandler({\n endpoint: '/trpc',\n req: new globalThis.Request(url, {\n method: req.method,\n headers: req.headers as any,\n body: req.method !== 'GET' && req.method !== 'HEAD' ? JSON.stringify(req.body) : undefined,\n }),\n router: appRouter,\n createContext,\n });\n\n res.status(response.status);\n response.headers.forEach((value, key) => res.setHeader(key, value));\n const body = await response.text();\n res.send(body);\n }\n}\n`);\n\n } else if (config.backend === 'express') {\n // ── Express: tRPC router, context, initialization ──\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'trpc.ts'), `import { initTRPC } from '@trpc/server';\nimport type { CreateExpressContextOptions } from '@trpc/server/adapters/express';\nimport superjson from 'superjson';\n\n/**\n * Context criado para cada request tRPC.\n * O req e res do Express ficam disponíveis para uso nas procedures.\n */\nexport interface Context {\n req: CreateExpressContextOptions['req'];\n res: CreateExpressContextOptions['res'];\n}\n\nexport function createContext({ req, res }: CreateExpressContextOptions): Context {\n return { req, res };\n}\n\nconst t = initTRPC.context<Context>().create({\n transformer: superjson,\n});\n\nexport const router = t.router;\nexport const publicProcedure = t.procedure;\nexport const middleware = t.middleware;\n`);\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'router.ts'), `import { z } from 'zod';\nimport { router, publicProcedure } from './trpc.js';\n\nexport const appRouter = router({\n hello: publicProcedure\n .input(z.object({ name: z.string().optional() }))\n .query(({ input }) => {\n return {\n greeting: \\`Olá \\${input.name ?? 'mundo'}!\\`,\n };\n }),\n\n getUser: publicProcedure\n .input(z.object({ id: z.string() }))\n .query(({ input }) => {\n // TODO: Buscar usuario no banco de dados\n return {\n id: input.id,\n name: 'Usuário Exemplo',\n email: 'usuario@exemplo.com',\n };\n }),\n});\n\nexport type AppRouter = typeof appRouter;\n`);\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'context.ts'), `/**\n * Re-exporta o contexto para facilitar importações.\n * Use: import { createContext } from './trpc/context.js';\n */\nexport { createContext, type Context } from './trpc.js';\n`);\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'index.ts'), `import express from 'express';\nimport { createExpressMiddleware } from '@trpc/server/adapters/express';\nimport { appRouter } from './router.js';\nimport { createContext } from './trpc.js';\n\n/**\n * Cria o middleware Express para tRPC.\n *\n * Uso no app principal:\n * import { trpcMiddleware } from './trpc/index.js';\n * app.use('/trpc', trpcMiddleware);\n */\nexport const trpcMiddleware = createExpressMiddleware({\n router: appRouter,\n createContext,\n});\n\nexport { appRouter, type AppRouter } from './router.js';\n`);\n\n } else {\n // ── Fastify: tRPC router, context, initialization ──\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'trpc.ts'), `import { initTRPC } from '@trpc/server';\nimport type { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';\nimport superjson from 'superjson';\n\n/**\n * Context criado para cada request tRPC.\n * O req e reply do Fastify ficam disponíveis para uso nas procedures.\n */\nexport interface Context {\n req: CreateFastifyContextOptions['req'];\n res: CreateFastifyContextOptions['res'];\n}\n\nexport function createContext({ req, res }: CreateFastifyContextOptions): Context {\n return { req, res };\n}\n\nconst t = initTRPC.context<Context>().create({\n transformer: superjson,\n});\n\nexport const router = t.router;\nexport const publicProcedure = t.procedure;\nexport const middleware = t.middleware;\n`);\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'router.ts'), `import { z } from 'zod';\nimport { router, publicProcedure } from './trpc.js';\n\nexport const appRouter = router({\n hello: publicProcedure\n .input(z.object({ name: z.string().optional() }))\n .query(({ input }) => {\n return {\n greeting: \\`Olá \\${input.name ?? 'mundo'}!\\`,\n };\n }),\n\n getUser: publicProcedure\n .input(z.object({ id: z.string() }))\n .query(({ input }) => {\n // TODO: Buscar usuario no banco de dados\n return {\n id: input.id,\n name: 'Usuário Exemplo',\n email: 'usuario@exemplo.com',\n };\n }),\n});\n\nexport type AppRouter = typeof appRouter;\n`);\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'context.ts'), `/**\n * Re-exporta o contexto para facilitar importações.\n * Use: import { createContext } from './trpc/context.js';\n */\nexport { createContext, type Context } from './trpc.js';\n`);\n\n await writeFile(path.join(apiDir, 'src', 'trpc', 'index.ts'), `import type { FastifyInstance } from 'fastify';\nimport { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify';\nimport { appRouter } from './router.js';\nimport { createContext } from './trpc.js';\n\n/**\n * Registra o plugin tRPC no Fastify.\n *\n * Uso:\n * import { registerTRPC } from './trpc/index.js';\n * await registerTRPC(app);\n */\nexport async function registerTRPC(app: FastifyInstance) {\n await app.register(fastifyTRPCPlugin, {\n prefix: '/trpc',\n trpcOptions: {\n router: appRouter,\n createContext,\n },\n });\n}\n\nexport { appRouter, type AppRouter } from './router.js';\n`);\n }\n\n // ── README com instrucoes para adicionar procedures ──\n await writeFile(path.join(apiDir, 'src', 'trpc', 'README.md'), `# tRPC\n\nEste diretório contém a configuração do tRPC para o seu projeto.\n\n## Estrutura\n\n- \\`trpc.ts\\` - Inicialização do tRPC (router, procedure, context)\n- \\`router.ts\\` / \\`trpc.router.ts\\` - Definição das procedures (appRouter)\n- \\`context.ts\\` - Contexto compartilhado entre procedures\n\n## Como adicionar novas procedures\n\n1. Abra o arquivo de router (\\`router.ts\\` ou \\`trpc.router.ts\\`)\n2. Adicione uma nova procedure ao \\`appRouter\\`:\n\n\\`\\`\\`typescript\nimport { z } from 'zod';\nimport { router, publicProcedure } from './trpc.js';\n\nexport const appRouter = router({\n // Procedures existentes...\n\n // Query - leitura de dados\n listPosts: publicProcedure\n .input(z.object({ limit: z.number().default(10) }))\n .query(async ({ input }) => {\n // Buscar posts no banco\n return [];\n }),\n\n // Mutation - escrita de dados\n createPost: publicProcedure\n .input(z.object({\n title: z.string().min(1),\n content: z.string(),\n }))\n .mutation(async ({ input }) => {\n // Criar post no banco\n return { id: '1', ...input };\n }),\n});\n\\`\\`\\`\n\n## Criando procedures protegidas\n\nPara criar procedures que requerem autenticação, crie um middleware:\n\n\\`\\`\\`typescript\nimport { TRPCError } from '@trpc/server';\nimport { middleware, publicProcedure } from './trpc.js';\n\nconst isAuthed = middleware(async ({ ctx, next }) => {\n // Verifique autenticação no contexto\n // if (!ctx.user) throw new TRPCError({ code: 'UNAUTHORIZED' });\n return next({ ctx });\n});\n\nexport const protectedProcedure = publicProcedure.use(isAuthed);\n\\`\\`\\`\n\n## Consumindo no frontend\n\nInstale os pacotes do cliente:\n\n\\`\\`\\`bash\nnpm install @trpc/client @trpc/react-query @tanstack/react-query superjson\n\\`\\`\\`\n\nConfigure o cliente apontando para o endpoint \\`/trpc\\` do seu backend.\n`);\n\n dependencies['@trpc/server'] = deps['@trpc/server'];\n dependencies['superjson'] = deps.superjson;\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 twilioSmsInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'twilio'));\n\n envEntries.push(\n { key: 'TWILIO_ACCOUNT_SID', value: '', category: 'Twilio', comment: 'Obtenha em https://console.twilio.com' },\n { key: 'TWILIO_AUTH_TOKEN', value: '', category: 'Twilio', comment: 'Obtenha em https://console.twilio.com' },\n { key: 'TWILIO_PHONE_NUMBER', value: '', category: 'Twilio', comment: 'Obtenha em https://console.twilio.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'twilio', 'twilio.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport twilio from 'twilio';\n\n@Injectable()\nexport class TwilioService {\n private client: ReturnType<typeof twilio>;\n private readonly phoneNumber: string;\n\n constructor(private configService: ConfigService) {\n this.client = twilio(\n this.configService.get('TWILIO_ACCOUNT_SID', ''),\n this.configService.get('TWILIO_AUTH_TOKEN', ''),\n );\n this.phoneNumber = this.configService.get('TWILIO_PHONE_NUMBER', '');\n }\n\n async sendSms(to: string, body: string) {\n return this.client.messages.create({\n to,\n from: this.phoneNumber,\n body,\n });\n }\n\n async sendVerification(to: string) {\n const code = Math.floor(100000 + Math.random() * 900000).toString();\n await this.sendSms(to, \\`Seu codigo de verificacao e: \\${code}\\`);\n return code;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'twilio', 'twilio.service.ts'), `import twilio from 'twilio';\n\nconst client = twilio(\n process.env.TWILIO_ACCOUNT_SID || '',\n process.env.TWILIO_AUTH_TOKEN || '',\n);\nconst PHONE_NUMBER = process.env.TWILIO_PHONE_NUMBER || '';\n\nexport async function sendSms(to: string, body: string) {\n return client.messages.create({\n to,\n from: PHONE_NUMBER,\n body,\n });\n}\n\nexport async function sendVerification(to: string) {\n const code = Math.floor(100000 + Math.random() * 900000).toString();\n await sendSms(to, \\`Seu codigo de verificacao e: \\${code}\\`);\n return code;\n}\n`);\n }\n\n dependencies['twilio'] = deps.twilio;\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 telegramBotInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'telegram'));\n\n envEntries.push(\n { key: 'TELEGRAM_BOT_TOKEN', value: '', category: 'Telegram', comment: 'Obtenha via @BotFather no Telegram' },\n { key: 'TELEGRAM_CHAT_ID', value: '', category: 'Telegram', comment: 'Chat ID para notificacoes' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'telegram', 'telegram.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { Telegraf } from 'telegraf';\n\n@Injectable()\nexport class TelegramService {\n private bot: Telegraf;\n private readonly chatId: string;\n\n constructor(private configService: ConfigService) {\n this.bot = new Telegraf(this.configService.get('TELEGRAM_BOT_TOKEN', ''));\n this.chatId = this.configService.get('TELEGRAM_CHAT_ID', '');\n }\n\n async sendMessage(text: string) {\n return this.bot.telegram.sendMessage(this.chatId, text);\n }\n\n async sendNotification(text: string) {\n return this.bot.telegram.sendMessage(this.chatId, \\`🔔 \\${text}\\`, {\n parse_mode: 'HTML',\n });\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'telegram', 'telegram.service.ts'), `import { Telegraf } from 'telegraf';\n\nconst bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN || '');\nconst CHAT_ID = process.env.TELEGRAM_CHAT_ID || '';\n\nexport async function sendMessage(text: string) {\n return bot.telegram.sendMessage(CHAT_ID, text);\n}\n\nexport async function sendNotification(text: string) {\n return bot.telegram.sendMessage(CHAT_ID, \\`🔔 \\${text}\\`, {\n parse_mode: 'HTML',\n });\n}\n`);\n }\n\n dependencies['telegraf'] = deps.telegraf;\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 openaiInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'openai'));\n\n envEntries.push(\n { key: 'OPENAI_API_KEY', value: '', category: 'OpenAI', comment: 'Obtenha em https://platform.openai.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'openai', 'openai.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport OpenAI from 'openai';\n\n@Injectable()\nexport class OpenAIService {\n private client: OpenAI;\n\n constructor(private configService: ConfigService) {\n this.client = new OpenAI({\n apiKey: this.configService.get('OPENAI_API_KEY', ''),\n });\n }\n\n async chat(messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[]) {\n const response = await this.client.chat.completions.create({\n model: 'gpt-4o',\n messages,\n });\n return response.choices[0]?.message?.content ?? '';\n }\n\n async completion(prompt: string) {\n return this.chat([{ role: 'user', content: prompt }]);\n }\n\n async embedding(text: string) {\n const response = await this.client.embeddings.create({\n model: 'text-embedding-3-small',\n input: text,\n });\n return response.data[0]?.embedding ?? [];\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'openai', 'openai.service.ts'), `import OpenAI from 'openai';\n\nconst client = new OpenAI({\n apiKey: process.env.OPENAI_API_KEY || '',\n});\n\nexport async function chat(messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[]) {\n const response = await client.chat.completions.create({\n model: 'gpt-4o',\n messages,\n });\n return response.choices[0]?.message?.content ?? '';\n}\n\nexport async function completion(prompt: string) {\n return chat([{ role: 'user', content: prompt }]);\n}\n\nexport async function embedding(text: string) {\n const response = await client.embeddings.create({\n model: 'text-embedding-3-small',\n input: text,\n });\n return response.data[0]?.embedding ?? [];\n}\n`);\n }\n\n dependencies['openai'] = deps.openai;\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 vercelAiInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'ai'));\n\n envEntries.push(\n { key: 'OPENAI_API_KEY', value: '', category: 'AI', comment: 'Provider padrao - Obtenha em https://platform.openai.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'ai', 'ai.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { generateText as aiGenerateText, streamText as aiStreamText } from 'ai';\nimport { openai } from '@ai-sdk/openai';\n\n@Injectable()\nexport class AIService {\n constructor(private configService: ConfigService) {\n process.env.OPENAI_API_KEY = this.configService.get('OPENAI_API_KEY', '');\n }\n\n async generateText(prompt: string) {\n const { text } = await aiGenerateText({\n model: openai('gpt-4o'),\n prompt,\n });\n return text;\n }\n\n async streamText(prompt: string) {\n const result = aiStreamText({\n model: openai('gpt-4o'),\n prompt,\n });\n return result;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'ai', 'ai.service.ts'), `import { generateText as aiGenerateText, streamText as aiStreamText } from 'ai';\nimport { openai } from '@ai-sdk/openai';\n\nexport async function generateText(prompt: string) {\n const { text } = await aiGenerateText({\n model: openai('gpt-4o'),\n prompt,\n });\n return text;\n}\n\nexport async function streamText(prompt: string) {\n const result = aiStreamText({\n model: openai('gpt-4o'),\n prompt,\n });\n return result;\n}\n`);\n }\n\n dependencies['ai'] = deps.ai;\n dependencies['@ai-sdk/openai'] = deps['@ai-sdk/openai'];\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 paypalInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'paypal'));\n\n envEntries.push(\n { key: 'PAYPAL_CLIENT_ID', value: '', category: 'PayPal', comment: 'Obtenha em https://developer.paypal.com' },\n { key: 'PAYPAL_CLIENT_SECRET', value: '', category: 'PayPal' },\n { key: 'PAYPAL_MODE', value: 'sandbox', category: 'PayPal', comment: 'sandbox ou live' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'paypal', 'paypal.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport checkoutNodeJssdk from '@paypal/checkout-server-sdk';\n\n@Injectable()\nexport class PayPalService {\n private client: checkoutNodeJssdk.core.PayPalHttpClient;\n\n constructor(private configService: ConfigService) {\n const clientId = this.configService.get('PAYPAL_CLIENT_ID', '');\n const clientSecret = this.configService.get('PAYPAL_CLIENT_SECRET', '');\n const mode = this.configService.get('PAYPAL_MODE', 'sandbox');\n\n const environment =\n mode === 'live'\n ? new checkoutNodeJssdk.core.LiveEnvironment(clientId, clientSecret)\n : new checkoutNodeJssdk.core.SandboxEnvironment(clientId, clientSecret);\n\n this.client = new checkoutNodeJssdk.core.PayPalHttpClient(environment);\n }\n\n async createOrder(amount: string, currency = 'USD') {\n const request = new checkoutNodeJssdk.orders.OrdersCreateRequest();\n request.prefer('return=representation');\n request.requestBody({\n intent: 'CAPTURE',\n purchase_units: [\n {\n amount: {\n currency_code: currency,\n value: amount,\n },\n },\n ],\n });\n\n const response = await this.client.execute(request);\n return response.result;\n }\n\n async capturePayment(orderId: string) {\n const request = new checkoutNodeJssdk.orders.OrdersCaptureRequest(orderId);\n request.requestBody({});\n const response = await this.client.execute(request);\n return response.result;\n }\n\n async getOrderDetails(orderId: string) {\n const request = new checkoutNodeJssdk.orders.OrdersGetRequest(orderId);\n const response = await this.client.execute(request);\n return response.result;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'paypal', 'paypal.service.ts'), `import checkoutNodeJssdk from '@paypal/checkout-server-sdk';\n\nconst clientId = process.env.PAYPAL_CLIENT_ID || '';\nconst clientSecret = process.env.PAYPAL_CLIENT_SECRET || '';\nconst mode = process.env.PAYPAL_MODE || 'sandbox';\n\nconst environment =\n mode === 'live'\n ? new checkoutNodeJssdk.core.LiveEnvironment(clientId, clientSecret)\n : new checkoutNodeJssdk.core.SandboxEnvironment(clientId, clientSecret);\n\nconst client = new checkoutNodeJssdk.core.PayPalHttpClient(environment);\n\nexport async function createOrder(amount: string, currency = 'USD') {\n const request = new checkoutNodeJssdk.orders.OrdersCreateRequest();\n request.prefer('return=representation');\n request.requestBody({\n intent: 'CAPTURE',\n purchase_units: [\n {\n amount: {\n currency_code: currency,\n value: amount,\n },\n },\n ],\n });\n\n const response = await client.execute(request);\n return response.result;\n}\n\nexport async function capturePayment(orderId: string) {\n const request = new checkoutNodeJssdk.orders.OrdersCaptureRequest(orderId);\n request.requestBody({});\n const response = await client.execute(request);\n return response.result;\n}\n\nexport async function getOrderDetails(orderId: string) {\n const request = new checkoutNodeJssdk.orders.OrdersGetRequest(orderId);\n const response = await client.execute(request);\n return response.result;\n}\n`);\n }\n\n dependencies['@paypal/checkout-server-sdk'] = deps['@paypal/checkout-server-sdk'];\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 vitestInstaller: InstallerFn = async (opts) => {\n const { apiDir, devDependencies, scripts } = opts;\n\n await ensureDir(path.join(apiDir, 'src', '__tests__'));\n\n // vitest.config.ts at apiDir root\n await writeFile(path.join(apiDir, 'vitest.config.ts'), `import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n test: {\n globals: true,\n environment: 'node',\n include: ['src/**/*.spec.ts'],\n setupFiles: ['src/__tests__/setup.ts'],\n coverage: {\n provider: 'v8',\n reporter: ['text', 'json', 'html'],\n },\n },\n});\n`);\n\n // Setup file\n await writeFile(path.join(apiDir, 'src', '__tests__', 'setup.ts'), `// Configuracao global dos testes\n// Este arquivo e executado antes de todos os testes\n\nbeforeAll(() => {\n // Setup global antes de todos os testes\n process.env.NODE_ENV = 'test';\n});\n\nafterAll(() => {\n // Cleanup global apos todos os testes\n});\n`);\n\n // Sample health check test\n await writeFile(path.join(apiDir, 'src', '__tests__', 'health.spec.ts'), `import { describe, it, expect } from 'vitest';\n\ndescribe('Health Check', () => {\n it('deve retornar status ok', () => {\n const health = {\n status: 'ok',\n timestamp: new Date().toISOString(),\n uptime: process.uptime(),\n };\n\n expect(health.status).toBe('ok');\n expect(health.timestamp).toBeDefined();\n expect(health.uptime).toBeGreaterThan(0);\n });\n\n it('deve validar formato da resposta de health', () => {\n const health = {\n status: 'ok',\n timestamp: new Date().toISOString(),\n uptime: process.uptime(),\n };\n\n expect(health).toHaveProperty('status');\n expect(health).toHaveProperty('timestamp');\n expect(health).toHaveProperty('uptime');\n });\n});\n`);\n\n devDependencies['vitest'] = deps.vitest;\n devDependencies['supertest'] = deps.supertest;\n devDependencies['@types/supertest'] = deps['@types/supertest'];\n\n scripts['test'] = 'vitest run';\n scripts['test:watch'] = 'vitest';\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 googleAnalyticsInstaller: InstallerFn = async (opts) => {\n const { config, webDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(webDir, 'src', 'analytics'));\n\n envEntries.push(\n { key: 'NEXT_PUBLIC_GA_MEASUREMENT_ID', value: '', category: 'Google Analytics', comment: 'Obtenha em https://analytics.google.com' },\n );\n\n if (config.frontend === 'nextjs') {\n // Next.js: use @next/third-parties/google\n await writeFile(path.join(webDir, 'src', 'analytics', 'GoogleAnalytics.tsx'), `'use client';\n\nimport { GoogleAnalytics as GA } from '@next/third-parties/google';\n\n/**\n * Componente Google Analytics para Next.js.\n *\n * Uso no layout principal (app/layout.tsx):\n *\n * import { GoogleAnalyticsProvider } from '@/analytics/GoogleAnalytics';\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html>\n * <body>\n * {children}\n * <GoogleAnalyticsProvider />\n * </body>\n * </html>\n * );\n * }\n */\nexport function GoogleAnalyticsProvider() {\n const gaId = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID;\n\n if (!gaId) return null;\n\n return <GA gaId={gaId} />;\n}\n\n/**\n * Envia um evento personalizado para o Google Analytics.\n */\nexport function trackEvent(eventName: string, params?: Record<string, string | number | boolean>) {\n if (typeof window !== 'undefined' && window.gtag) {\n window.gtag('event', eventName, params);\n }\n}\n\n// Declaracao global para o gtag\ndeclare global {\n interface Window {\n gtag: (...args: any[]) => void;\n }\n}\n`);\n\n dependencies['@next/third-parties'] = deps['@next/third-parties'];\n } else {\n // Outros frameworks: utility com script tag injection\n await writeFile(path.join(webDir, 'src', 'analytics', 'analytics.ts'), `/**\n * Google Analytics 4 - Integracao para SPA.\n *\n * Uso:\n * import { initGA, trackPageView, trackEvent } from './analytics/analytics';\n *\n * // Na inicializacao do app:\n * initGA();\n *\n * // Em mudancas de rota:\n * trackPageView('/pagina');\n *\n * // Para eventos customizados:\n * trackEvent('click_button', { label: 'signup' });\n */\n\nconst GA_MEASUREMENT_ID = import.meta.env.VITE_GA_MEASUREMENT_ID || '';\n\n/**\n * Injeta o script do Google Analytics 4 no documento.\n */\nexport function initGA(): void {\n if (!GA_MEASUREMENT_ID || typeof document === 'undefined') return;\n\n // gtag.js script\n const script = document.createElement('script');\n script.async = true;\n script.src = \\`https://www.googletagmanager.com/gtag/js?id=\\${GA_MEASUREMENT_ID}\\`;\n document.head.appendChild(script);\n\n // gtag config\n const inlineScript = document.createElement('script');\n inlineScript.textContent = \\`\n window.dataLayer = window.dataLayer || [];\n function gtag(){dataLayer.push(arguments);}\n gtag('js', new Date());\n gtag('config', '\\${GA_MEASUREMENT_ID}');\n \\`;\n document.head.appendChild(inlineScript);\n}\n\n/**\n * Registra uma visualizacao de pagina.\n */\nexport function trackPageView(pagePath: string): void {\n if (typeof window !== 'undefined' && window.gtag) {\n window.gtag('config', GA_MEASUREMENT_ID, { page_path: pagePath });\n }\n}\n\n/**\n * Envia um evento personalizado para o Google Analytics.\n */\nexport function trackEvent(eventName: string, params?: Record<string, string | number | boolean>): void {\n if (typeof window !== 'undefined' && window.gtag) {\n window.gtag('event', eventName, params);\n }\n}\n\n// Declaracao global para o gtag\ndeclare global {\n interface Window {\n gtag: (...args: any[]) => void;\n dataLayer: any[];\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\nexport const meilisearchInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, dockerServices } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'search'));\n\n envEntries.push(\n { key: 'MEILISEARCH_HOST', value: 'http://localhost:7700', category: 'Meilisearch' },\n { key: 'MEILISEARCH_API_KEY', value: 'masterKey', category: 'Meilisearch' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'meilisearch.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { MeiliSearch, type SearchParams, type Index } from 'meilisearch';\n\n@Injectable()\nexport class MeilisearchService {\n private client: MeiliSearch;\n\n constructor(private configService: ConfigService) {\n this.client = new MeiliSearch({\n host: this.configService.get('MEILISEARCH_HOST', 'http://localhost:7700'),\n apiKey: this.configService.get('MEILISEARCH_API_KEY', 'masterKey'),\n });\n }\n\n async search(indexName: string, query: string, options?: SearchParams) {\n const index = this.client.index(indexName);\n return index.search(query, options);\n }\n\n async addDocuments(indexName: string, documents: Record<string, any>[]) {\n const index = this.client.index(indexName);\n return index.addDocuments(documents);\n }\n\n async deleteDocument(indexName: string, id: string | number) {\n const index = this.client.index(indexName);\n return index.deleteDocument(id);\n }\n\n async getIndex(indexName: string): Promise<Index> {\n return this.client.getIndex(indexName);\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'meilisearch.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { MeilisearchService } from './meilisearch.service';\n\n@Global()\n@Module({\n providers: [MeilisearchService],\n exports: [MeilisearchService],\n})\nexport class MeilisearchModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'meilisearch.ts'), `import { MeiliSearch, type SearchParams } from 'meilisearch';\n\nconst client = new MeiliSearch({\n host: process.env.MEILISEARCH_HOST || 'http://localhost:7700',\n apiKey: process.env.MEILISEARCH_API_KEY || 'masterKey',\n});\n\nexport async function search(indexName: string, query: string, options?: SearchParams) {\n const index = client.index(indexName);\n return index.search(query, options);\n}\n\nexport async function addDocuments(indexName: string, documents: Record<string, any>[]) {\n const index = client.index(indexName);\n return index.addDocuments(documents);\n}\n\nexport async function deleteDocument(indexName: string, id: string | number) {\n const index = client.index(indexName);\n return index.deleteDocument(id);\n}\n\nexport async function getIndex(indexName: string) {\n return client.getIndex(indexName);\n}\n\nexport default { search, addDocuments, deleteDocument, getIndex };\n`);\n }\n\n dependencies['meilisearch'] = deps.meilisearch;\n\n dockerServices.push(` meilisearch:\\n image: getmeili/meilisearch:latest\\n ports:\\n - \"7700:7700\"\\n environment:\\n MEILI_MASTER_KEY: masterKey\\n volumes:\\n - meilisearch_data:/meili_data`);\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 nodeCronInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'jobs'));\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'jobs', 'cron.service.ts'), `import { Injectable, OnModuleInit } from '@nestjs/common';\nimport * as cron from 'node-cron';\n\n@Injectable()\nexport class CronService implements OnModuleInit {\n private tasks: cron.ScheduledTask[] = [];\n\n onModuleInit() {\n this.registerJobs();\n console.log('Cron jobs registrados');\n }\n\n /**\n * Registra todos os cron jobs da aplicacao.\n * Adicione novos jobs aqui.\n */\n registerJobs() {\n // Executa a cada minuto\n this.schedule('* * * * *', 'heartbeat', () => {\n console.log(\\`[Cron] Heartbeat: \\${new Date().toISOString()}\\`);\n });\n\n // Executa todos os dias a meia-noite\n this.schedule('0 0 * * *', 'daily-cleanup', async () => {\n console.log('[Cron] Executando limpeza diaria...');\n // TODO: Implemente a logica de limpeza\n });\n\n // Executa toda segunda-feira as 9h\n this.schedule('0 9 * * 1', 'weekly-report', async () => {\n console.log('[Cron] Gerando relatorio semanal...');\n // TODO: Implemente a logica do relatorio\n });\n }\n\n private schedule(expression: string, name: string, handler: () => void | Promise<void>) {\n const task = cron.schedule(expression, async () => {\n try {\n await handler();\n } catch (error) {\n console.error(\\`[Cron] Erro no job \"\\${name}\":\\`, error);\n }\n });\n this.tasks.push(task);\n }\n\n onModuleDestroy() {\n this.tasks.forEach((task) => task.stop());\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'jobs', 'example.job.ts'), `/**\n * Exemplo de job que pode ser importado e utilizado pelo CronService.\n *\n * Uso:\n * import { cleanupExpiredSessions } from './example.job';\n *\n * // No CronService.registerJobs():\n * this.schedule('0 */6 * * *', 'cleanup-sessions', cleanupExpiredSessions);\n */\n\nexport async function cleanupExpiredSessions(): Promise<void> {\n console.log('[Job] Limpando sessoes expiradas...');\n // TODO: Implemente a logica de limpeza de sessoes\n}\n\nexport async function sendDailyDigest(): Promise<void> {\n console.log('[Job] Enviando resumo diario...');\n // TODO: Implemente a logica de envio de resumo\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'jobs', 'cron.ts'), `import cron from 'node-cron';\n\n/**\n * Registra todos os cron jobs da aplicacao.\n * Chame esta funcao na inicializacao do servidor:\n *\n * import { registerCronJobs } from './jobs/cron.js';\n * registerCronJobs();\n */\nexport function registerCronJobs(): void {\n // Executa a cada minuto\n cron.schedule('* * * * *', () => {\n console.log(\\`[Cron] Heartbeat: \\${new Date().toISOString()}\\`);\n });\n\n // Executa todos os dias a meia-noite\n cron.schedule('0 0 * * *', async () => {\n console.log('[Cron] Executando limpeza diaria...');\n // TODO: Implemente a logica de limpeza\n });\n\n // Executa toda segunda-feira as 9h\n cron.schedule('0 9 * * 1', async () => {\n console.log('[Cron] Gerando relatorio semanal...');\n // TODO: Implemente a logica do relatorio\n });\n\n console.log('Cron jobs registrados');\n}\n\nexport default { registerCronJobs };\n`);\n\n await writeFile(path.join(apiDir, 'src', 'jobs', 'example.job.ts'), `/**\n * Exemplo de job que pode ser agendado com node-cron.\n *\n * Uso:\n * import cron from 'node-cron';\n * import { cleanupExpiredSessions } from './example.job.js';\n *\n * cron.schedule('0 */6 * * *', cleanupExpiredSessions);\n */\n\nexport async function cleanupExpiredSessions(): Promise<void> {\n console.log('[Job] Limpando sessoes expiradas...');\n // TODO: Implemente a logica de limpeza de sessoes\n}\n\nexport async function sendDailyDigest(): Promise<void> {\n console.log('[Job] Enviando resumo diario...');\n // TODO: Implemente a logica de envio de resumo\n}\n`);\n }\n\n dependencies['node-cron'] = deps['node-cron'];\n devDependencies['@types/node-cron'] = deps['@types/node-cron'];\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 pdfkitInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies, devDependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'pdf'));\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'pdf', 'pdf.service.ts'), `import { Injectable } from '@nestjs/common';\nimport PDFDocument from 'pdfkit';\n\ninterface InvoiceData {\n invoiceNumber: string;\n date: string;\n customerName: string;\n customerEmail: string;\n items: Array<{\n description: string;\n quantity: number;\n unitPrice: number;\n }>;\n}\n\ninterface ReportData {\n title: string;\n generatedAt: string;\n sections: Array<{\n heading: string;\n content: string;\n }>;\n}\n\n@Injectable()\nexport class PdfService {\n async generateInvoice(data: InvoiceData): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const doc = new PDFDocument({ margin: 50 });\n const chunks: Buffer[] = [];\n\n doc.on('data', (chunk: Buffer) => chunks.push(chunk));\n doc.on('end', () => resolve(Buffer.concat(chunks)));\n doc.on('error', reject);\n\n // Cabecalho\n doc.fontSize(20).text('FATURA', { align: 'center' });\n doc.moveDown();\n doc.fontSize(10)\n .text(\\`Numero: \\${data.invoiceNumber}\\`)\n .text(\\`Data: \\${data.date}\\`)\n .text(\\`Cliente: \\${data.customerName}\\`)\n .text(\\`Email: \\${data.customerEmail}\\`);\n doc.moveDown();\n\n // Tabela de itens\n doc.fontSize(12).text('Itens:', { underline: true });\n doc.moveDown(0.5);\n\n let total = 0;\n for (const item of data.items) {\n const subtotal = item.quantity * item.unitPrice;\n total += subtotal;\n doc.fontSize(10)\n .text(\\`\\${item.description} | Qtd: \\${item.quantity} | Unitario: R$ \\${item.unitPrice.toFixed(2)} | Subtotal: R$ \\${subtotal.toFixed(2)}\\`);\n }\n\n doc.moveDown();\n doc.fontSize(14).text(\\`Total: R$ \\${total.toFixed(2)}\\`, { align: 'right' });\n\n doc.end();\n });\n }\n\n async generateReport(data: ReportData): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const doc = new PDFDocument({ margin: 50 });\n const chunks: Buffer[] = [];\n\n doc.on('data', (chunk: Buffer) => chunks.push(chunk));\n doc.on('end', () => resolve(Buffer.concat(chunks)));\n doc.on('error', reject);\n\n // Titulo\n doc.fontSize(24).text(data.title, { align: 'center' });\n doc.moveDown(0.5);\n doc.fontSize(10).text(\\`Gerado em: \\${data.generatedAt}\\`, { align: 'center' });\n doc.moveDown();\n\n // Secoes\n for (const section of data.sections) {\n doc.fontSize(16).text(section.heading, { underline: true });\n doc.moveDown(0.5);\n doc.fontSize(11).text(section.content);\n doc.moveDown();\n }\n\n doc.end();\n });\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'pdf', 'pdf.ts'), `import PDFDocument from 'pdfkit';\n\ninterface InvoiceData {\n invoiceNumber: string;\n date: string;\n customerName: string;\n customerEmail: string;\n items: Array<{\n description: string;\n quantity: number;\n unitPrice: number;\n }>;\n}\n\ninterface ReportData {\n title: string;\n generatedAt: string;\n sections: Array<{\n heading: string;\n content: string;\n }>;\n}\n\nexport async function generateInvoice(data: InvoiceData): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const doc = new PDFDocument({ margin: 50 });\n const chunks: Buffer[] = [];\n\n doc.on('data', (chunk: Buffer) => chunks.push(chunk));\n doc.on('end', () => resolve(Buffer.concat(chunks)));\n doc.on('error', reject);\n\n // Cabecalho\n doc.fontSize(20).text('FATURA', { align: 'center' });\n doc.moveDown();\n doc.fontSize(10)\n .text(\\`Numero: \\${data.invoiceNumber}\\`)\n .text(\\`Data: \\${data.date}\\`)\n .text(\\`Cliente: \\${data.customerName}\\`)\n .text(\\`Email: \\${data.customerEmail}\\`);\n doc.moveDown();\n\n // Tabela de itens\n doc.fontSize(12).text('Itens:', { underline: true });\n doc.moveDown(0.5);\n\n let total = 0;\n for (const item of data.items) {\n const subtotal = item.quantity * item.unitPrice;\n total += subtotal;\n doc.fontSize(10)\n .text(\\`\\${item.description} | Qtd: \\${item.quantity} | Unitario: R$ \\${item.unitPrice.toFixed(2)} | Subtotal: R$ \\${subtotal.toFixed(2)}\\`);\n }\n\n doc.moveDown();\n doc.fontSize(14).text(\\`Total: R$ \\${total.toFixed(2)}\\`, { align: 'right' });\n\n doc.end();\n });\n}\n\nexport async function generateReport(data: ReportData): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const doc = new PDFDocument({ margin: 50 });\n const chunks: Buffer[] = [];\n\n doc.on('data', (chunk: Buffer) => chunks.push(chunk));\n doc.on('end', () => resolve(Buffer.concat(chunks)));\n doc.on('error', reject);\n\n // Titulo\n doc.fontSize(24).text(data.title, { align: 'center' });\n doc.moveDown(0.5);\n doc.fontSize(10).text(\\`Gerado em: \\${data.generatedAt}\\`, { align: 'center' });\n doc.moveDown();\n\n // Secoes\n for (const section of data.sections) {\n doc.fontSize(16).text(section.heading, { underline: true });\n doc.moveDown(0.5);\n doc.fontSize(11).text(section.content);\n doc.moveDown();\n }\n\n doc.end();\n });\n}\n\nexport default { generateInvoice, generateReport };\n`);\n }\n\n dependencies['pdfkit'] = deps.pdfkit;\n devDependencies['@types/pdfkit'] = deps['@types/pdfkit'];\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 healthChecksInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'health'));\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'health', 'health.controller.ts'), `import { Controller, Get } from '@nestjs/common';\nimport {\n HealthCheckService,\n HealthCheck,\n MemoryHealthIndicator,\n DiskHealthIndicator,${config.usePrisma ? '\\n PrismaHealthIndicator,' : ''}\n} from '@nestjs/terminus';${config.usePrisma ? \"\\nimport { PrismaClient } from '@prisma/client';\" : ''}\n\n@Controller('api/health')\nexport class HealthController {\n constructor(\n private health: HealthCheckService,\n private memory: MemoryHealthIndicator,\n private disk: DiskHealthIndicator,${config.usePrisma ? '\\n private prisma: PrismaHealthIndicator,\\n private prismaClient: PrismaClient,' : ''}\n ) {}\n\n @Get()\n @HealthCheck()\n check() {\n return this.health.check([\n // Memoria: heap nao deve exceder 200MB\n () => this.memory.checkHeap('memory_heap', 200 * 1024 * 1024),\n\n // Memoria: RSS nao deve exceder 300MB\n () => this.memory.checkRSS('memory_rss', 300 * 1024 * 1024),\n\n // Disco: nao deve exceder 90% de uso\n () => this.disk.checkStorage('disk', { path: '/', thresholdPercent: 0.9 }),${config.usePrisma ? \"\\n\\n // Database\\n () => this.prisma.pingCheck('database', this.prismaClient),\" : ''}\n ]);\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'health', 'health.module.ts'), `import { Module } from '@nestjs/common';\nimport { TerminusModule } from '@nestjs/terminus';\nimport { HealthController } from './health.controller';\n\n@Module({\n imports: [TerminusModule],\n controllers: [HealthController],\n})\nexport class HealthModule {}\n`);\n\n dependencies['@nestjs/terminus'] = deps['@nestjs/terminus'];\n\n } else if (config.backend === 'express') {\n const dbCheckCode = config.usePrisma\n ? `\n // Database check\n try {\n const { PrismaClient } = await import('@prisma/client');\n const prisma = new PrismaClient();\n await prisma.$queryRaw\\`SELECT 1\\`;\n await prisma.$disconnect();\n checks.database = { status: 'ok' };\n } catch (err) {\n checks.database = { status: 'error', message: (err as Error).message };\n status = 'degraded';\n }`\n : config.useMongoose\n ? `\n // Database check\n try {\n const mongoose = await import('mongoose');\n const state = mongoose.default.connection.readyState;\n checks.database = { status: state === 1 ? 'ok' : 'error' };\n if (state !== 1) status = 'degraded';\n } catch (err) {\n checks.database = { status: 'error', message: (err as Error).message };\n status = 'degraded';\n }`\n : '';\n\n const redisCheckCode = config.redis\n ? `\n // Redis check\n try {\n const redis = await import('../infra/redis/redis.js');\n await redis.default.ping();\n checks.redis = { status: 'ok' };\n } catch (err) {\n checks.redis = { status: 'error', message: (err as Error).message };\n status = 'degraded';\n }`\n : '';\n\n await writeFile(path.join(apiDir, 'src', 'health', 'health.routes.ts'), `import { Router, type Request, type Response } from 'express';\n\nconst router = Router();\n\n/**\n * GET /api/health\n * Retorna o status de saude da aplicacao.\n */\nrouter.get('/api/health', async (_req: Request, res: Response) => {\n let status = 'ok';\n const checks: Record<string, { status: string; message?: string }> = {};\n\n // Memory check\n const memUsage = process.memoryUsage();\n const heapUsedMB = Math.round(memUsage.heapUsed / 1024 / 1024);\n checks.memory = {\n status: heapUsedMB < 200 ? 'ok' : 'warning',\n message: \\`Heap: \\${heapUsedMB}MB\\`,\n };\n if (heapUsedMB >= 200) status = 'degraded';${dbCheckCode}${redisCheckCode}\n\n res.status(status === 'ok' ? 200 : 503).json({\n status,\n timestamp: new Date().toISOString(),\n uptime: process.uptime(),\n checks,\n });\n});\n\nexport default router;\n`);\n\n } else {\n // Fastify\n const dbCheckCode = config.usePrisma\n ? `\n // Database check\n try {\n const { PrismaClient } = await import('@prisma/client');\n const prisma = new PrismaClient();\n await prisma.$queryRaw\\`SELECT 1\\`;\n await prisma.$disconnect();\n checks.database = { status: 'ok' };\n } catch (err) {\n checks.database = { status: 'error', message: (err as Error).message };\n status = 'degraded';\n }`\n : config.useMongoose\n ? `\n // Database check\n try {\n const mongoose = await import('mongoose');\n const state = mongoose.default.connection.readyState;\n checks.database = { status: state === 1 ? 'ok' : 'error' };\n if (state !== 1) status = 'degraded';\n } catch (err) {\n checks.database = { status: 'error', message: (err as Error).message };\n status = 'degraded';\n }`\n : '';\n\n const redisCheckCode = config.redis\n ? `\n // Redis check\n try {\n const redis = await import('../infra/redis/redis.js');\n await redis.default.ping();\n checks.redis = { status: 'ok' };\n } catch (err) {\n checks.redis = { status: 'error', message: (err as Error).message };\n status = 'degraded';\n }`\n : '';\n\n await writeFile(path.join(apiDir, 'src', 'health', 'health.routes.ts'), `import type { FastifyInstance } from 'fastify';\n\n/**\n * Plugin Fastify para health checks.\n *\n * Uso:\n * import { healthRoutes } from './health/health.routes.js';\n * app.register(healthRoutes);\n */\nexport async function healthRoutes(app: FastifyInstance): Promise<void> {\n app.get('/api/health', async (_request, reply) => {\n let status = 'ok';\n const checks: Record<string, { status: string; message?: string }> = {};\n\n // Memory check\n const memUsage = process.memoryUsage();\n const heapUsedMB = Math.round(memUsage.heapUsed / 1024 / 1024);\n checks.memory = {\n status: heapUsedMB < 200 ? 'ok' : 'warning',\n message: \\`Heap: \\${heapUsedMB}MB\\`,\n };\n if (heapUsedMB >= 200) status = 'degraded';${dbCheckCode}${redisCheckCode}\n\n const statusCode = status === 'ok' ? 200 : 503;\n return reply.status(statusCode).send({\n status,\n timestamp: new Date().toISOString(),\n uptime: process.uptime(),\n checks,\n });\n });\n}\n\nexport default healthRoutes;\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 facebookOauthInstaller: 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: 'FACEBOOK_APP_ID', value: '', category: 'Facebook OAuth', comment: 'Obtenha em https://developers.facebook.com' },\n { key: 'FACEBOOK_APP_SECRET', value: '', category: 'Facebook OAuth' },\n { key: 'FACEBOOK_CALLBACK_URL', value: 'http://localhost:3001/api/auth/facebook/callback', category: 'Facebook OAuth' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'facebook.strategy.ts'), `import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-facebook';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class FacebookStrategy extends PassportStrategy(Strategy, 'facebook') {\n constructor(configService: ConfigService) {\n super({\n clientID: configService.get<string>('FACEBOOK_APP_ID'),\n clientSecret: configService.get<string>('FACEBOOK_APP_SECRET'),\n callbackURL: configService.get<string>('FACEBOOK_CALLBACK_URL'),\n profileFields: ['id', 'emails', 'name', 'displayName', 'photos'],\n scope: ['email'],\n });\n }\n\n async validate(\n accessToken: string,\n refreshToken: string,\n profile: any,\n done: (err: any, user?: any) => void,\n ) {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n facebookId: 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', 'facebook.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/facebook')\nexport class FacebookController {\n @Get()\n @UseGuards(AuthGuard('facebook'))\n async facebookAuth() {\n // Redireciona para o Facebook\n }\n\n @Get('callback')\n @UseGuards(AuthGuard('facebook'))\n async facebookCallback(@Req() req: Request, @Res() res: Response) {\n const user = req.user;\n // TODO: Criar/buscar usuario no banco, gerar JWT\n console.log('Facebook 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', 'facebook.routes.ts'), `import { Router } from 'express';\nimport passport from 'passport';\nimport { Strategy as FacebookStrategy } from 'passport-facebook';\n\npassport.use(\n new FacebookStrategy(\n {\n clientID: process.env.FACEBOOK_APP_ID || '',\n clientSecret: process.env.FACEBOOK_APP_SECRET || '',\n callbackURL: process.env.FACEBOOK_CALLBACK_URL || 'http://localhost:3001/api/auth/facebook/callback',\n profileFields: ['id', 'emails', 'name', 'displayName', 'photos'],\n },\n async (accessToken: string, refreshToken: string, profile: any, done: (err: any, user?: any) => void) => {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n facebookId: 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 facebookRouter = Router();\n\nfacebookRouter.get('/', passport.authenticate('facebook', { scope: ['email'] }));\n\nfacebookRouter.get(\n '/callback',\n passport.authenticate('facebook', { session: false }),\n (req, res) => {\n // TODO: Gerar JWT e redirecionar\n console.log('Facebook user:', req.user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n);\n\nexport { facebookRouter };\n`);\n\n dependencies['passport'] = deps.passport;\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'facebook.routes.ts'), `import type { FastifyInstance } from 'fastify';\n\n// Para Fastify, recomendamos usar @fastify/oauth2\n// npm install @fastify/oauth2\nexport async function facebookAuthRoutes(app: FastifyInstance) {\n // TODO: Configurar @fastify/oauth2 para Facebook\n // Documentacao: https://github.com/fastify/fastify-oauth2\n\n app.get('/api/auth/facebook', async (request, reply) => {\n const clientId = process.env.FACEBOOK_APP_ID;\n const redirectUri = process.env.FACEBOOK_CALLBACK_URL;\n const url = \\`https://www.facebook.com/v18.0/dialog/oauth?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&scope=email\\`;\n reply.redirect(url);\n });\n\n app.get('/api/auth/facebook/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: 'Facebook OAuth callback', code };\n });\n}\n`);\n }\n\n dependencies['passport-facebook'] = deps['passport-facebook'];\n devDependencies['@types/passport-facebook'] = deps['@types/passport-facebook'];\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 microsoftOauthInstaller: 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: 'MICROSOFT_CLIENT_ID', value: '', category: 'Microsoft OAuth', comment: 'Obtenha em https://portal.azure.com' },\n { key: 'MICROSOFT_CLIENT_SECRET', value: '', category: 'Microsoft OAuth' },\n { key: 'MICROSOFT_TENANT_ID', value: 'common', category: 'Microsoft OAuth' },\n { key: 'MICROSOFT_CALLBACK_URL', value: 'http://localhost:3001/api/auth/microsoft/callback', category: 'Microsoft OAuth' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'microsoft.strategy.ts'), `import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { OIDCStrategy } from 'passport-azure-ad';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class MicrosoftStrategy extends PassportStrategy(OIDCStrategy, 'microsoft') {\n constructor(configService: ConfigService) {\n super({\n identityMetadata: \\`https://login.microsoftonline.com/\\${configService.get<string>('MICROSOFT_TENANT_ID')}/v2.0/.well-known/openid-configuration\\`,\n clientID: configService.get<string>('MICROSOFT_CLIENT_ID'),\n clientSecret: configService.get<string>('MICROSOFT_CLIENT_SECRET'),\n responseType: 'code',\n responseMode: 'query',\n redirectUrl: configService.get<string>('MICROSOFT_CALLBACK_URL'),\n allowHttpForRedirectUrl: true,\n scope: ['profile', 'email', 'openid'],\n });\n }\n\n async validate(\n iss: string,\n sub: string,\n profile: any,\n accessToken: string,\n refreshToken: string,\n done: (err: any, user?: any) => void,\n ) {\n const user = {\n email: profile._json?.email || profile.upn,\n name: profile.displayName,\n microsoftId: profile.oid,\n };\n done(null, user);\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'microsoft.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/microsoft')\nexport class MicrosoftController {\n @Get()\n @UseGuards(AuthGuard('microsoft'))\n async microsoftAuth() {\n // Redireciona para o Microsoft\n }\n\n @Get('callback')\n @UseGuards(AuthGuard('microsoft'))\n async microsoftCallback(@Req() req: Request, @Res() res: Response) {\n const user = req.user;\n // TODO: Criar/buscar usuario no banco, gerar JWT\n console.log('Microsoft 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', 'microsoft.routes.ts'), `import { Router } from 'express';\nimport passport from 'passport';\nimport { OIDCStrategy } from 'passport-azure-ad';\n\npassport.use('microsoft',\n new OIDCStrategy(\n {\n identityMetadata: \\`https://login.microsoftonline.com/\\${process.env.MICROSOFT_TENANT_ID || 'common'}/v2.0/.well-known/openid-configuration\\`,\n clientID: process.env.MICROSOFT_CLIENT_ID || '',\n clientSecret: process.env.MICROSOFT_CLIENT_SECRET || '',\n responseType: 'code',\n responseMode: 'query',\n redirectUrl: process.env.MICROSOFT_CALLBACK_URL || 'http://localhost:3001/api/auth/microsoft/callback',\n allowHttpForRedirectUrl: true,\n scope: ['profile', 'email', 'openid'],\n },\n async (iss: string, sub: string, profile: any, accessToken: string, refreshToken: string, done: (err: any, user?: any) => void) => {\n const user = {\n email: profile._json?.email || profile.upn,\n name: profile.displayName,\n microsoftId: profile.oid,\n };\n // TODO: Criar/buscar usuario no banco\n done(null, user);\n }\n )\n);\n\nconst microsoftRouter = Router();\n\nmicrosoftRouter.get('/', passport.authenticate('microsoft', { scope: ['profile', 'email', 'openid'] }));\n\nmicrosoftRouter.get(\n '/callback',\n passport.authenticate('microsoft', { session: false }),\n (req, res) => {\n // TODO: Gerar JWT e redirecionar\n console.log('Microsoft user:', req.user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n);\n\nexport { microsoftRouter };\n`);\n\n dependencies['passport'] = deps.passport;\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'microsoft.routes.ts'), `import type { FastifyInstance } from 'fastify';\n\n// Para Fastify, recomendamos usar @fastify/oauth2\n// npm install @fastify/oauth2\nexport async function microsoftAuthRoutes(app: FastifyInstance) {\n // TODO: Configurar @fastify/oauth2 para Microsoft\n // Documentacao: https://github.com/fastify/fastify-oauth2\n\n app.get('/api/auth/microsoft', async (request, reply) => {\n const clientId = process.env.MICROSOFT_CLIENT_ID;\n const tenantId = process.env.MICROSOFT_TENANT_ID || 'common';\n const redirectUri = process.env.MICROSOFT_CALLBACK_URL;\n const url = \\`https://login.microsoftonline.com/\\${tenantId}/oauth2/v2.0/authorize?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&response_type=code&scope=openid+profile+email\\`;\n reply.redirect(url);\n });\n\n app.get('/api/auth/microsoft/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: 'Microsoft OAuth callback', code };\n });\n}\n`);\n }\n\n dependencies['passport-azure-ad'] = deps['passport-azure-ad'];\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 linkedinOauthInstaller: 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: 'LINKEDIN_CLIENT_ID', value: '', category: 'LinkedIn OAuth', comment: 'Obtenha em https://www.linkedin.com/developers' },\n { key: 'LINKEDIN_CLIENT_SECRET', value: '', category: 'LinkedIn OAuth' },\n { key: 'LINKEDIN_CALLBACK_URL', value: 'http://localhost:3001/api/auth/linkedin/callback', category: 'LinkedIn OAuth' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'linkedin.strategy.ts'), `import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-linkedin-oauth2';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class LinkedInStrategy extends PassportStrategy(Strategy, 'linkedin') {\n constructor(configService: ConfigService) {\n super({\n clientID: configService.get<string>('LINKEDIN_CLIENT_ID'),\n clientSecret: configService.get<string>('LINKEDIN_CLIENT_SECRET'),\n callbackURL: configService.get<string>('LINKEDIN_CALLBACK_URL'),\n scope: ['openid', 'profile', 'email'],\n });\n }\n\n async validate(\n accessToken: string,\n refreshToken: string,\n profile: any,\n done: (err: any, user?: any) => void,\n ) {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n linkedinId: 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', 'linkedin.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/linkedin')\nexport class LinkedInController {\n @Get()\n @UseGuards(AuthGuard('linkedin'))\n async linkedinAuth() {\n // Redireciona para o LinkedIn\n }\n\n @Get('callback')\n @UseGuards(AuthGuard('linkedin'))\n async linkedinCallback(@Req() req: Request, @Res() res: Response) {\n const user = req.user;\n // TODO: Criar/buscar usuario no banco, gerar JWT\n console.log('LinkedIn 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', 'linkedin.routes.ts'), `import { Router } from 'express';\nimport passport from 'passport';\nimport { Strategy as LinkedInStrategy } from 'passport-linkedin-oauth2';\n\npassport.use(\n new LinkedInStrategy(\n {\n clientID: process.env.LINKEDIN_CLIENT_ID || '',\n clientSecret: process.env.LINKEDIN_CLIENT_SECRET || '',\n callbackURL: process.env.LINKEDIN_CALLBACK_URL || 'http://localhost:3001/api/auth/linkedin/callback',\n scope: ['openid', 'profile', 'email'],\n },\n async (accessToken: string, refreshToken: string, profile: any, done: (err: any, user?: any) => void) => {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n linkedinId: 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 linkedinRouter = Router();\n\nlinkedinRouter.get('/', passport.authenticate('linkedin'));\n\nlinkedinRouter.get(\n '/callback',\n passport.authenticate('linkedin', { session: false }),\n (req, res) => {\n // TODO: Gerar JWT e redirecionar\n console.log('LinkedIn user:', req.user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n);\n\nexport { linkedinRouter };\n`);\n\n dependencies['passport'] = deps.passport;\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'linkedin.routes.ts'), `import type { FastifyInstance } from 'fastify';\n\n// Para Fastify, recomendamos usar @fastify/oauth2\n// npm install @fastify/oauth2\nexport async function linkedinAuthRoutes(app: FastifyInstance) {\n // TODO: Configurar @fastify/oauth2 para LinkedIn\n // Documentacao: https://github.com/fastify/fastify-oauth2\n\n app.get('/api/auth/linkedin', async (request, reply) => {\n const clientId = process.env.LINKEDIN_CLIENT_ID;\n const redirectUri = process.env.LINKEDIN_CALLBACK_URL;\n const url = \\`https://www.linkedin.com/oauth/v2/authorization?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&response_type=code&scope=openid%20profile%20email\\`;\n reply.redirect(url);\n });\n\n app.get('/api/auth/linkedin/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: 'LinkedIn OAuth callback', code };\n });\n}\n`);\n }\n\n dependencies['passport-linkedin-oauth2'] = deps['passport-linkedin-oauth2'];\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 twitterOauthInstaller: 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: 'TWITTER_API_KEY', value: '', category: 'Twitter OAuth', comment: 'Obtenha em https://developer.twitter.com' },\n { key: 'TWITTER_API_SECRET', value: '', category: 'Twitter OAuth' },\n { key: 'TWITTER_CALLBACK_URL', value: 'http://localhost:3001/api/auth/twitter/callback', category: 'Twitter OAuth' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'twitter.strategy.ts'), `import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-twitter';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class TwitterStrategy extends PassportStrategy(Strategy, 'twitter') {\n constructor(configService: ConfigService) {\n super({\n consumerKey: configService.get<string>('TWITTER_API_KEY'),\n consumerSecret: configService.get<string>('TWITTER_API_SECRET'),\n callbackURL: configService.get<string>('TWITTER_CALLBACK_URL'),\n includeEmail: true,\n });\n }\n\n async validate(\n accessToken: string,\n refreshToken: string,\n profile: any,\n done: (err: any, user?: any) => void,\n ) {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n twitterId: profile.id,\n username: profile.username,\n avatar: profile.photos?.[0]?.value,\n };\n done(null, user);\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'twitter.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/twitter')\nexport class TwitterController {\n @Get()\n @UseGuards(AuthGuard('twitter'))\n async twitterAuth() {\n // Redireciona para o Twitter\n }\n\n @Get('callback')\n @UseGuards(AuthGuard('twitter'))\n async twitterCallback(@Req() req: Request, @Res() res: Response) {\n const user = req.user;\n // TODO: Criar/buscar usuario no banco, gerar JWT\n console.log('Twitter 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', 'twitter.routes.ts'), `import { Router } from 'express';\nimport passport from 'passport';\nimport { Strategy as TwitterStrategy } from 'passport-twitter';\n\npassport.use(\n new TwitterStrategy(\n {\n consumerKey: process.env.TWITTER_API_KEY || '',\n consumerSecret: process.env.TWITTER_API_SECRET || '',\n callbackURL: process.env.TWITTER_CALLBACK_URL || 'http://localhost:3001/api/auth/twitter/callback',\n includeEmail: true,\n },\n async (accessToken: string, refreshToken: string, profile: any, done: (err: any, user?: any) => void) => {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n twitterId: profile.id,\n username: profile.username,\n avatar: profile.photos?.[0]?.value,\n };\n // TODO: Criar/buscar usuario no banco\n done(null, user);\n }\n )\n);\n\nconst twitterRouter = Router();\n\ntwitterRouter.get('/', passport.authenticate('twitter'));\n\ntwitterRouter.get(\n '/callback',\n passport.authenticate('twitter', { session: false }),\n (req, res) => {\n // TODO: Gerar JWT e redirecionar\n console.log('Twitter user:', req.user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n);\n\nexport { twitterRouter };\n`);\n\n dependencies['passport'] = deps.passport;\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'twitter.routes.ts'), `import type { FastifyInstance } from 'fastify';\n\n// Para Fastify, recomendamos usar @fastify/oauth2\n// npm install @fastify/oauth2\nexport async function twitterAuthRoutes(app: FastifyInstance) {\n // TODO: Configurar @fastify/oauth2 para Twitter\n // Documentacao: https://github.com/fastify/fastify-oauth2\n\n app.get('/api/auth/twitter', async (request, reply) => {\n // Twitter OAuth 1.0a requer fluxo diferente\n // Considere usar Twitter OAuth 2.0 com PKCE para novos projetos\n const clientId = process.env.TWITTER_API_KEY;\n const redirectUri = process.env.TWITTER_CALLBACK_URL;\n const url = \\`https://twitter.com/i/oauth2/authorize?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&response_type=code&scope=tweet.read%20users.read%20offline.access\\`;\n reply.redirect(url);\n });\n\n app.get('/api/auth/twitter/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: 'Twitter OAuth callback', code };\n });\n}\n`);\n }\n\n dependencies['passport-twitter'] = deps['passport-twitter'];\n devDependencies['@types/passport-twitter'] = deps['@types/passport-twitter'];\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 spotifyOauthInstaller: 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: 'SPOTIFY_CLIENT_ID', value: '', category: 'Spotify OAuth', comment: 'Obtenha em https://developer.spotify.com/dashboard' },\n { key: 'SPOTIFY_CLIENT_SECRET', value: '', category: 'Spotify OAuth' },\n { key: 'SPOTIFY_CALLBACK_URL', value: 'http://localhost:3001/api/auth/spotify/callback', category: 'Spotify OAuth' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'spotify.strategy.ts'), `import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-spotify';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class SpotifyStrategy extends PassportStrategy(Strategy, 'spotify') {\n constructor(configService: ConfigService) {\n super({\n clientID: configService.get<string>('SPOTIFY_CLIENT_ID'),\n clientSecret: configService.get<string>('SPOTIFY_CLIENT_SECRET'),\n callbackURL: configService.get<string>('SPOTIFY_CALLBACK_URL'),\n scope: ['user-read-email', 'user-read-private'],\n });\n }\n\n async validate(\n accessToken: string,\n refreshToken: string,\n expires_in: number,\n profile: any,\n done: (err: any, user?: any) => void,\n ) {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n spotifyId: 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', 'spotify.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/spotify')\nexport class SpotifyController {\n @Get()\n @UseGuards(AuthGuard('spotify'))\n async spotifyAuth() {\n // Redireciona para o Spotify\n }\n\n @Get('callback')\n @UseGuards(AuthGuard('spotify'))\n async spotifyCallback(@Req() req: Request, @Res() res: Response) {\n const user = req.user;\n // TODO: Criar/buscar usuario no banco, gerar JWT\n console.log('Spotify 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', 'spotify.routes.ts'), `import { Router } from 'express';\nimport passport from 'passport';\nimport { Strategy as SpotifyStrategy } from 'passport-spotify';\n\npassport.use(\n new SpotifyStrategy(\n {\n clientID: process.env.SPOTIFY_CLIENT_ID || '',\n clientSecret: process.env.SPOTIFY_CLIENT_SECRET || '',\n callbackURL: process.env.SPOTIFY_CALLBACK_URL || 'http://localhost:3001/api/auth/spotify/callback',\n },\n async (accessToken: string, refreshToken: string, expires_in: number, profile: any, done: (err: any, user?: any) => void) => {\n const user = {\n email: profile.emails?.[0]?.value,\n name: profile.displayName,\n spotifyId: 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 spotifyRouter = Router();\n\nspotifyRouter.get('/', passport.authenticate('spotify', { scope: ['user-read-email', 'user-read-private'] }));\n\nspotifyRouter.get(\n '/callback',\n passport.authenticate('spotify', { session: false }),\n (req, res) => {\n // TODO: Gerar JWT e redirecionar\n console.log('Spotify user:', req.user);\n res.redirect(process.env.APP_URL || 'http://localhost:3000');\n }\n);\n\nexport { spotifyRouter };\n`);\n\n dependencies['passport'] = deps.passport;\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'spotify.routes.ts'), `import type { FastifyInstance } from 'fastify';\n\n// Para Fastify, recomendamos usar @fastify/oauth2\n// npm install @fastify/oauth2\nexport async function spotifyAuthRoutes(app: FastifyInstance) {\n // TODO: Configurar @fastify/oauth2 para Spotify\n // Documentacao: https://github.com/fastify/fastify-oauth2\n\n app.get('/api/auth/spotify', async (request, reply) => {\n const clientId = process.env.SPOTIFY_CLIENT_ID;\n const redirectUri = process.env.SPOTIFY_CALLBACK_URL;\n const url = \\`https://accounts.spotify.com/authorize?client_id=\\${clientId}&redirect_uri=\\${redirectUri}&response_type=code&scope=user-read-email%20user-read-private\\`;\n reply.redirect(url);\n });\n\n app.get('/api/auth/spotify/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: 'Spotify OAuth callback', code };\n });\n}\n`);\n }\n\n dependencies['passport-spotify'] = deps['passport-spotify'];\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 auth0Installer: 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: 'AUTH0_DOMAIN', value: '', category: 'Auth0', comment: 'Obtenha em https://manage.auth0.com' },\n { key: 'AUTH0_CLIENT_ID', value: '', category: 'Auth0' },\n { key: 'AUTH0_CLIENT_SECRET', value: '', category: 'Auth0' },\n { key: 'AUTH0_CALLBACK_URL', value: 'http://localhost:3001/api/auth/callback', category: 'Auth0' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth0.guard.ts'), `import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport * as jwt from 'jsonwebtoken';\nimport * as jwksClient from 'jwks-rsa';\n\n@Injectable()\nexport class Auth0Guard implements CanActivate {\n private client: jwksClient.JwksClient;\n\n constructor(private configService: ConfigService) {\n const domain = this.configService.get<string>('AUTH0_DOMAIN');\n this.client = jwksClient({\n jwksUri: \\`https://\\${domain}/.well-known/jwks.json\\`,\n });\n }\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest();\n const authHeader = request.headers.authorization;\n\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n throw new UnauthorizedException('Token nao fornecido');\n }\n\n const token = authHeader.split(' ')[1];\n\n try {\n const decoded = jwt.decode(token, { complete: true });\n if (!decoded || !decoded.header.kid) {\n throw new UnauthorizedException('Token invalido');\n }\n\n const key = await this.client.getSigningKey(decoded.header.kid);\n const signingKey = key.getPublicKey();\n const domain = this.configService.get<string>('AUTH0_DOMAIN');\n const clientId = this.configService.get<string>('AUTH0_CLIENT_ID');\n\n const payload = jwt.verify(token, signingKey, {\n algorithms: ['RS256'],\n issuer: \\`https://\\${domain}/\\`,\n audience: clientId,\n });\n\n request.user = payload;\n return true;\n } catch (error) {\n throw new UnauthorizedException('Token invalido ou expirado');\n }\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth0.controller.ts'), `import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { Auth0Guard } from './auth0.guard';\nimport type { Request } from 'express';\n\n@Controller('auth')\nexport class Auth0Controller {\n @Get('profile')\n @UseGuards(Auth0Guard)\n async getProfile(@Req() req: Request) {\n return { user: req.user };\n }\n}\n`);\n\n dependencies['jsonwebtoken'] = deps.jsonwebtoken;\n } else if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth0.routes.ts'), `import { Router } from 'express';\nimport { auth, requiresAuth } from 'express-openid-connect';\n\nconst auth0Config = {\n authRequired: false,\n auth0Logout: true,\n secret: process.env.AUTH0_CLIENT_SECRET || '',\n baseURL: process.env.APP_URL || 'http://localhost:3001',\n clientID: process.env.AUTH0_CLIENT_ID || '',\n issuerBaseURL: \\`https://\\${process.env.AUTH0_DOMAIN}\\`,\n routes: {\n callback: '/api/auth/callback',\n login: '/api/auth/login',\n logout: '/api/auth/logout',\n },\n};\n\nconst auth0Router = Router();\n\n// Middleware de autenticacao Auth0\nauth0Router.use(auth(auth0Config));\n\n// Rota protegida - perfil do usuario\nauth0Router.get('/profile', requiresAuth(), (req, res) => {\n res.json({ user: (req as any).oidc?.user });\n});\n\n// Rota para verificar status de autenticacao\nauth0Router.get('/status', (req, res) => {\n res.json({ isAuthenticated: (req as any).oidc?.isAuthenticated() || false });\n});\n\nexport { auth0Router };\n`);\n\n dependencies['express-openid-connect'] = deps['express-openid-connect'];\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'auth0.routes.ts'), `import type { FastifyInstance, FastifyRequest } from 'fastify';\nimport * as jwt from 'jsonwebtoken';\n\n// Validacao manual de JWT do Auth0 para Fastify\nasync function verifyAuth0Token(request: FastifyRequest): Promise<any> {\n const authHeader = request.headers.authorization;\n\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n throw new Error('Token nao fornecido');\n }\n\n const token = authHeader.split(' ')[1];\n const domain = process.env.AUTH0_DOMAIN;\n const clientId = process.env.AUTH0_CLIENT_ID;\n\n // Buscar JWKS do Auth0\n const response = await fetch(\\`https://\\${domain}/.well-known/jwks.json\\`);\n const jwks = await response.json();\n\n const decoded = jwt.decode(token, { complete: true }) as any;\n if (!decoded || !decoded.header.kid) {\n throw new Error('Token invalido');\n }\n\n const key = jwks.keys.find((k: any) => k.kid === decoded.header.kid);\n if (!key) {\n throw new Error('Chave nao encontrada');\n }\n\n // Converter JWK para PEM (simplificado - use jose ou jwks-rsa em producao)\n const publicKey = \\`-----BEGIN CERTIFICATE-----\\\\n\\${key.x5c[0]}\\\\n-----END CERTIFICATE-----\\`;\n\n return jwt.verify(token, publicKey, {\n algorithms: ['RS256'],\n issuer: \\`https://\\${domain}/\\`,\n audience: clientId,\n });\n}\n\nexport async function auth0Routes(app: FastifyInstance) {\n app.get('/api/auth/login', async (request, reply) => {\n const domain = process.env.AUTH0_DOMAIN;\n const clientId = process.env.AUTH0_CLIENT_ID;\n const callbackUrl = process.env.AUTH0_CALLBACK_URL;\n const url = \\`https://\\${domain}/authorize?client_id=\\${clientId}&redirect_uri=\\${callbackUrl}&response_type=code&scope=openid%20profile%20email\\`;\n reply.redirect(url);\n });\n\n app.get('/api/auth/callback', async (request) => {\n const { code } = request.query as { code: string };\n // TODO: Trocar code por tokens usando Auth0 token endpoint\n return { message: 'Auth0 callback', code };\n });\n\n app.get('/api/auth/profile', async (request, reply) => {\n try {\n const user = await verifyAuth0Token(request);\n return { user };\n } catch (error: any) {\n reply.code(401).send({ error: error.message });\n }\n });\n}\n`);\n\n dependencies['jsonwebtoken'] = deps.jsonwebtoken;\n }\n\n dependencies['auth0'] = deps.auth0;\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 supabaseAuthInstaller: 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: 'SUPABASE_URL', value: '', category: 'Supabase Auth', comment: 'Obtenha em https://supabase.com/dashboard' },\n { key: 'SUPABASE_ANON_KEY', value: '', category: 'Supabase Auth' },\n { key: 'SUPABASE_SERVICE_ROLE_KEY', value: '', category: 'Supabase Auth' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'supabase.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { createClient, SupabaseClient } from '@supabase/supabase-js';\n\n@Injectable()\nexport class SupabaseAuthService {\n private supabase: SupabaseClient;\n private supabaseAdmin: SupabaseClient;\n\n constructor(private configService: ConfigService) {\n const url = this.configService.get<string>('SUPABASE_URL') || '';\n const anonKey = this.configService.get<string>('SUPABASE_ANON_KEY') || '';\n const serviceRoleKey = this.configService.get<string>('SUPABASE_SERVICE_ROLE_KEY') || '';\n\n this.supabase = createClient(url, anonKey);\n this.supabaseAdmin = createClient(url, serviceRoleKey);\n }\n\n async signUp(email: string, password: string) {\n const { data, error } = await this.supabase.auth.signUp({\n email,\n password,\n });\n if (error) throw error;\n return data;\n }\n\n async signIn(email: string, password: string) {\n const { data, error } = await this.supabase.auth.signInWithPassword({\n email,\n password,\n });\n if (error) throw error;\n return data;\n }\n\n async signOut(accessToken: string) {\n // Usar admin client para revogar sessao\n const { error } = await this.supabaseAdmin.auth.admin.signOut(accessToken);\n if (error) throw error;\n return { message: 'Logout realizado com sucesso' };\n }\n\n async getUser(accessToken: string) {\n const { data, error } = await this.supabase.auth.getUser(accessToken);\n if (error) throw error;\n return data.user;\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'supabase.controller.ts'), `import { Controller, Post, Get, Body, Headers, UnauthorizedException } from '@nestjs/common';\nimport { SupabaseAuthService } from './supabase.service';\n\n@Controller('auth')\nexport class SupabaseAuthController {\n constructor(private readonly supabaseAuth: SupabaseAuthService) {}\n\n @Post('signup')\n async signUp(@Body() body: { email: string; password: string }) {\n return this.supabaseAuth.signUp(body.email, body.password);\n }\n\n @Post('signin')\n async signIn(@Body() body: { email: string; password: string }) {\n return this.supabaseAuth.signIn(body.email, body.password);\n }\n\n @Post('signout')\n async signOut(@Headers('authorization') auth: string) {\n const token = auth?.replace('Bearer ', '');\n if (!token) throw new UnauthorizedException('Token nao fornecido');\n return this.supabaseAuth.signOut(token);\n }\n\n @Get('me')\n async getUser(@Headers('authorization') auth: string) {\n const token = auth?.replace('Bearer ', '');\n if (!token) throw new UnauthorizedException('Token nao fornecido');\n return this.supabaseAuth.getUser(token);\n }\n}\n`);\n } else if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'auth', 'supabase.service.ts'), `import { createClient, SupabaseClient } from '@supabase/supabase-js';\n\nconst supabaseUrl = process.env.SUPABASE_URL || '';\nconst supabaseAnonKey = process.env.SUPABASE_ANON_KEY || '';\nconst supabaseServiceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY || '';\n\nconst supabase: SupabaseClient = createClient(supabaseUrl, supabaseAnonKey);\nconst supabaseAdmin: SupabaseClient = createClient(supabaseUrl, supabaseServiceRoleKey);\n\nexport async function signUp(email: string, password: string) {\n const { data, error } = await supabase.auth.signUp({ email, password });\n if (error) throw error;\n return data;\n}\n\nexport async function signIn(email: string, password: string) {\n const { data, error } = await supabase.auth.signInWithPassword({ email, password });\n if (error) throw error;\n return data;\n}\n\nexport async function signOut(accessToken: string) {\n const { error } = await supabaseAdmin.auth.admin.signOut(accessToken);\n if (error) throw error;\n return { message: 'Logout realizado com sucesso' };\n}\n\nexport async function getUser(accessToken: string) {\n const { data, error } = await supabase.auth.getUser(accessToken);\n if (error) throw error;\n return data.user;\n}\n\nexport { supabase, supabaseAdmin };\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'supabase.routes.ts'), `import { Router } from 'express';\nimport { signUp, signIn, signOut, getUser } from './supabase.service';\n\nconst supabaseRouter = Router();\n\nsupabaseRouter.post('/signup', async (req, res) => {\n try {\n const { email, password } = req.body;\n const data = await signUp(email, password);\n res.json(data);\n } catch (error: any) {\n res.status(400).json({ error: error.message });\n }\n});\n\nsupabaseRouter.post('/signin', async (req, res) => {\n try {\n const { email, password } = req.body;\n const data = await signIn(email, password);\n res.json(data);\n } catch (error: any) {\n res.status(401).json({ error: error.message });\n }\n});\n\nsupabaseRouter.post('/signout', async (req, res) => {\n try {\n const token = req.headers.authorization?.replace('Bearer ', '');\n if (!token) return res.status(401).json({ error: 'Token nao fornecido' });\n const data = await signOut(token);\n res.json(data);\n } catch (error: any) {\n res.status(400).json({ error: error.message });\n }\n});\n\nsupabaseRouter.get('/me', async (req, res) => {\n try {\n const token = req.headers.authorization?.replace('Bearer ', '');\n if (!token) return res.status(401).json({ error: 'Token nao fornecido' });\n const user = await getUser(token);\n res.json({ user });\n } catch (error: any) {\n res.status(401).json({ error: error.message });\n }\n});\n\nexport { supabaseRouter };\n`);\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'auth', 'supabase.service.ts'), `import { createClient, SupabaseClient } from '@supabase/supabase-js';\n\nconst supabaseUrl = process.env.SUPABASE_URL || '';\nconst supabaseAnonKey = process.env.SUPABASE_ANON_KEY || '';\nconst supabaseServiceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY || '';\n\nconst supabase: SupabaseClient = createClient(supabaseUrl, supabaseAnonKey);\nconst supabaseAdmin: SupabaseClient = createClient(supabaseUrl, supabaseServiceRoleKey);\n\nexport async function signUp(email: string, password: string) {\n const { data, error } = await supabase.auth.signUp({ email, password });\n if (error) throw error;\n return data;\n}\n\nexport async function signIn(email: string, password: string) {\n const { data, error } = await supabase.auth.signInWithPassword({ email, password });\n if (error) throw error;\n return data;\n}\n\nexport async function signOut(accessToken: string) {\n const { error } = await supabaseAdmin.auth.admin.signOut(accessToken);\n if (error) throw error;\n return { message: 'Logout realizado com sucesso' };\n}\n\nexport async function getUser(accessToken: string) {\n const { data, error } = await supabase.auth.getUser(accessToken);\n if (error) throw error;\n return data.user;\n}\n\nexport { supabase, supabaseAdmin };\n`);\n\n await writeFile(path.join(apiDir, 'src', 'auth', 'supabase.routes.ts'), `import type { FastifyInstance } from 'fastify';\nimport { signUp, signIn, signOut, getUser } from './supabase.service';\n\nexport async function supabaseAuthRoutes(app: FastifyInstance) {\n app.post('/api/auth/signup', async (request, reply) => {\n try {\n const { email, password } = request.body as { email: string; password: string };\n const data = await signUp(email, password);\n return data;\n } catch (error: any) {\n reply.code(400).send({ error: error.message });\n }\n });\n\n app.post('/api/auth/signin', async (request, reply) => {\n try {\n const { email, password } = request.body as { email: string; password: string };\n const data = await signIn(email, password);\n return data;\n } catch (error: any) {\n reply.code(401).send({ error: error.message });\n }\n });\n\n app.post('/api/auth/signout', async (request, reply) => {\n try {\n const token = request.headers.authorization?.replace('Bearer ', '');\n if (!token) {\n reply.code(401).send({ error: 'Token nao fornecido' });\n return;\n }\n const data = await signOut(token);\n return data;\n } catch (error: any) {\n reply.code(400).send({ error: error.message });\n }\n });\n\n app.get('/api/auth/me', async (request, reply) => {\n try {\n const token = request.headers.authorization?.replace('Bearer ', '');\n if (!token) {\n reply.code(401).send({ error: 'Token nao fornecido' });\n return;\n }\n const user = await getUser(token);\n return { user };\n } catch (error: any) {\n reply.code(401).send({ error: error.message });\n }\n });\n}\n`);\n }\n\n dependencies['@supabase/supabase-js'] = deps['@supabase/supabase-js'];\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 sendgridInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'email'));\n\n envEntries.push(\n { key: 'SENDGRID_API_KEY', value: '', category: 'SendGrid', comment: 'Obtenha em https://app.sendgrid.com' },\n { key: 'EMAIL_FROM', value: 'noreply@example.com', category: 'SendGrid' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'sendgrid.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport sgMail from '@sendgrid/mail';\n\n@Injectable()\nexport class SendgridService {\n constructor(private configService: ConfigService) {\n sgMail.setApiKey(this.configService.get('SENDGRID_API_KEY', ''));\n }\n\n async send(params: {\n to: string | string[];\n subject: string;\n html: string;\n }): Promise<void> {\n await sgMail.send({\n from: this.configService.get('EMAIL_FROM', 'noreply@example.com'),\n to: params.to,\n subject: params.subject,\n html: params.html,\n });\n }\n\n async sendWithTemplate(params: {\n to: string | string[];\n templateId: string;\n dynamicTemplateData?: Record<string, any>;\n }): Promise<void> {\n await sgMail.send({\n from: this.configService.get('EMAIL_FROM', 'noreply@example.com'),\n to: params.to,\n templateId: params.templateId,\n dynamicTemplateData: params.dynamicTemplateData,\n });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'sendgrid.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { SendgridService } from './sendgrid.service';\n\n@Global()\n@Module({\n providers: [SendgridService],\n exports: [SendgridService],\n})\nexport class SendgridModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'sendgrid.ts'), `import sgMail from '@sendgrid/mail';\n\nsgMail.setApiKey(process.env.SENDGRID_API_KEY || '');\n\nexport async function sendEmail(params: {\n to: string | string[];\n subject: string;\n html: string;\n}): Promise<void> {\n await sgMail.send({\n from: process.env.EMAIL_FROM || 'noreply@example.com',\n to: params.to,\n subject: params.subject,\n html: params.html,\n });\n}\n\nexport async function sendWithTemplate(params: {\n to: string | string[];\n templateId: string;\n dynamicTemplateData?: Record<string, any>;\n}): Promise<void> {\n await sgMail.send({\n from: process.env.EMAIL_FROM || 'noreply@example.com',\n to: params.to,\n templateId: params.templateId,\n dynamicTemplateData: params.dynamicTemplateData,\n });\n}\n\nexport default { sendEmail, sendWithTemplate };\n`);\n }\n\n dependencies['@sendgrid/mail'] = deps['@sendgrid/mail'];\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 amazonSesInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'email'));\n\n envEntries.push(\n { key: 'AWS_ACCESS_KEY_ID', value: '', category: 'Amazon SES', comment: 'Obtenha no AWS IAM Console' },\n { key: 'AWS_SECRET_ACCESS_KEY', value: '', category: 'Amazon SES' },\n { key: 'AWS_REGION', value: 'us-east-1', category: 'Amazon SES' },\n { key: 'EMAIL_FROM', value: 'noreply@example.com', category: 'Amazon SES' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'ses.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { SESClient, SendEmailCommand } from '@aws-sdk/client-ses';\n\n@Injectable()\nexport class SesService {\n private client: SESClient;\n\n constructor(private configService: ConfigService) {\n this.client = new SESClient({\n region: this.configService.get('AWS_REGION', 'us-east-1'),\n credentials: {\n accessKeyId: this.configService.get('AWS_ACCESS_KEY_ID', ''),\n secretAccessKey: this.configService.get('AWS_SECRET_ACCESS_KEY', ''),\n },\n });\n }\n\n async send(params: {\n to: string | string[];\n subject: string;\n html: string;\n }): Promise<void> {\n const toAddresses = Array.isArray(params.to) ? params.to : [params.to];\n\n const command = new SendEmailCommand({\n Source: this.configService.get('EMAIL_FROM', 'noreply@example.com'),\n Destination: {\n ToAddresses: toAddresses,\n },\n Message: {\n Subject: { Data: params.subject },\n Body: {\n Html: { Data: params.html },\n },\n },\n });\n\n await this.client.send(command);\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'ses.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { SesService } from './ses.service';\n\n@Global()\n@Module({\n providers: [SesService],\n exports: [SesService],\n})\nexport class SesModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'email', 'ses.ts'), `import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses';\n\nconst client = new SESClient({\n region: process.env.AWS_REGION || 'us-east-1',\n credentials: {\n accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || '',\n },\n});\n\nexport async function sendEmail(params: {\n to: string | string[];\n subject: string;\n html: string;\n}): Promise<void> {\n const toAddresses = Array.isArray(params.to) ? params.to : [params.to];\n\n const command = new SendEmailCommand({\n Source: process.env.EMAIL_FROM || 'noreply@example.com',\n Destination: {\n ToAddresses: toAddresses,\n },\n Message: {\n Subject: { Data: params.subject },\n Body: {\n Html: { Data: params.html },\n },\n },\n });\n\n await client.send(command);\n}\n\nexport default { sendEmail };\n`);\n }\n\n dependencies['@aws-sdk/client-ses'] = deps['@aws-sdk/client-ses'];\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 posthogInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'analytics'));\n\n envEntries.push(\n { key: 'POSTHOG_API_KEY', value: '', category: 'PostHog', comment: 'Obtenha em https://posthog.com' },\n { key: 'POSTHOG_HOST', value: 'https://app.posthog.com', category: 'PostHog' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'analytics', 'posthog.service.ts'), `import { Injectable, OnModuleDestroy } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { PostHog } from 'posthog-node';\n\n@Injectable()\nexport class PostHogService implements OnModuleDestroy {\n private client: PostHog;\n\n constructor(private configService: ConfigService) {\n this.client = new PostHog(\n this.configService.get('POSTHOG_API_KEY', ''),\n { host: this.configService.get('POSTHOG_HOST', 'https://app.posthog.com') },\n );\n }\n\n capture(distinctId: string, event: string, properties?: Record<string, any>) {\n this.client.capture({\n distinctId,\n event,\n properties,\n });\n }\n\n identify(distinctId: string, properties?: Record<string, any>) {\n this.client.identify({\n distinctId,\n properties,\n });\n }\n\n async onModuleDestroy() {\n await this.client.shutdown();\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'analytics', 'posthog.ts'), `import { PostHog } from 'posthog-node';\n\nconst client = new PostHog(\n process.env.POSTHOG_API_KEY || '',\n { host: process.env.POSTHOG_HOST || 'https://app.posthog.com' },\n);\n\nexport function capture(distinctId: string, event: string, properties?: Record<string, any>) {\n client.capture({\n distinctId,\n event,\n properties,\n });\n}\n\nexport function identify(distinctId: string, properties?: Record<string, any>) {\n client.identify({\n distinctId,\n properties,\n });\n}\n\nexport async function shutdown() {\n await client.shutdown();\n}\n\nexport default { capture, identify, shutdown };\n`);\n }\n\n dependencies['posthog-node'] = deps['posthog-node'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\n\nexport const plausibleInstaller: InstallerFn = async (opts) => {\n const { config, webDir, envEntries } = opts;\n\n await ensureDir(path.join(webDir, 'src', 'analytics'));\n\n envEntries.push(\n { key: 'NEXT_PUBLIC_PLAUSIBLE_DOMAIN', value: '', category: 'Plausible', comment: 'Seu dominio registrado no Plausible (ex: meusite.com.br)' },\n );\n\n if (config.frontend === 'nextjs') {\n await writeFile(path.join(webDir, 'src', 'analytics', 'PlausibleAnalytics.tsx'), `'use client';\n\nimport Script from 'next/script';\n\n/**\n * Componente Plausible Analytics para Next.js.\n *\n * Uso no layout principal (app/layout.tsx):\n *\n * import { PlausibleAnalytics } from '@/analytics/PlausibleAnalytics';\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html>\n * <body>\n * {children}\n * <PlausibleAnalytics />\n * </body>\n * </html>\n * );\n * }\n */\nexport function PlausibleAnalytics() {\n const domain = process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN;\n\n if (!domain) return null;\n\n return (\n <Script\n defer\n data-domain={domain}\n src=\"https://plausible.io/js/script.js\"\n strategy=\"afterInteractive\"\n />\n );\n}\n\n/**\n * Envia um evento personalizado para o Plausible.\n */\nexport function trackEvent(eventName: string, props?: Record<string, string | number | boolean>) {\n if (typeof window !== 'undefined' && window.plausible) {\n window.plausible(eventName, { props });\n }\n}\n\n// Declaracao global para o plausible\ndeclare global {\n interface Window {\n plausible: (eventName: string, options?: { props?: Record<string, string | number | boolean> }) => void;\n }\n}\n`);\n } else {\n await writeFile(path.join(webDir, 'src', 'analytics', 'plausible.ts'), `/**\n * Plausible Analytics - Integracao para SPA.\n *\n * Uso:\n * import { initPlausible, trackEvent } from './analytics/plausible';\n *\n * // Na inicializacao do app:\n * initPlausible();\n *\n * // Para eventos customizados:\n * trackEvent('signup', { plan: 'pro' });\n */\n\nconst PLAUSIBLE_DOMAIN = import.meta.env.VITE_PLAUSIBLE_DOMAIN || '';\n\n/**\n * Injeta o script do Plausible Analytics no documento.\n */\nexport function initPlausible(): void {\n if (!PLAUSIBLE_DOMAIN || typeof document === 'undefined') return;\n\n const script = document.createElement('script');\n script.defer = true;\n script.setAttribute('data-domain', PLAUSIBLE_DOMAIN);\n script.src = 'https://plausible.io/js/script.js';\n document.head.appendChild(script);\n}\n\n/**\n * Envia um evento personalizado para o Plausible.\n */\nexport function trackEvent(eventName: string, props?: Record<string, string | number | boolean>): void {\n if (typeof window !== 'undefined' && window.plausible) {\n window.plausible(eventName, { props });\n }\n}\n\n// Declaracao global para o plausible\ndeclare global {\n interface Window {\n plausible: (eventName: string, options?: { props?: Record<string, string | number | boolean> }) => void;\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\nexport const mixpanelInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'analytics'));\n\n envEntries.push(\n { key: 'MIXPANEL_TOKEN', value: '', category: 'Mixpanel', comment: 'Obtenha em https://mixpanel.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'analytics', 'mixpanel.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Mixpanel from 'mixpanel';\n\n@Injectable()\nexport class MixpanelService {\n private client: Mixpanel.Mixpanel;\n\n constructor(private configService: ConfigService) {\n this.client = Mixpanel.init(this.configService.get('MIXPANEL_TOKEN', ''));\n }\n\n track(event: string, properties?: Record<string, any>) {\n this.client.track(event, properties);\n }\n\n identify(distinctId: string) {\n this.client.people.set(distinctId, {});\n }\n\n setProfile(distinctId: string, properties: Record<string, any>) {\n this.client.people.set(distinctId, properties);\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'analytics', 'mixpanel.ts'), `import Mixpanel from 'mixpanel';\n\nconst client = Mixpanel.init(process.env.MIXPANEL_TOKEN || '');\n\nexport function track(event: string, properties?: Record<string, any>) {\n client.track(event, properties);\n}\n\nexport function identify(distinctId: string) {\n client.people.set(distinctId, {});\n}\n\nexport function setProfile(distinctId: string, properties: Record<string, any>) {\n client.people.set(distinctId, properties);\n}\n\nexport default { track, identify, setProfile };\n`);\n }\n\n dependencies['mixpanel'] = deps.mixpanel;\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 algoliaInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'search'));\n\n envEntries.push(\n { key: 'ALGOLIA_APP_ID', value: '', category: 'Algolia', comment: 'Obtenha em https://www.algolia.com/account/api-keys' },\n { key: 'ALGOLIA_API_KEY', value: '', category: 'Algolia', comment: 'Admin API Key' },\n { key: 'ALGOLIA_SEARCH_KEY', value: '', category: 'Algolia', comment: 'Search-Only API Key' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'algolia.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { algoliasearch, type SearchClient } from 'algoliasearch';\n\n@Injectable()\nexport class AlgoliaService {\n private client: SearchClient;\n\n constructor(private configService: ConfigService) {\n this.client = algoliasearch(\n this.configService.get('ALGOLIA_APP_ID', ''),\n this.configService.get('ALGOLIA_API_KEY', ''),\n );\n }\n\n async search(indexName: string, query: string) {\n return this.client.searchSingleIndex({\n indexName,\n searchParams: { query },\n });\n }\n\n async addObjects(indexName: string, objects: Record<string, any>[]) {\n return this.client.saveObjects({\n indexName,\n objects,\n });\n }\n\n async deleteObject(indexName: string, objectId: string) {\n return this.client.deleteObject({\n indexName,\n objectID: objectId,\n });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'algolia.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { AlgoliaService } from './algolia.service';\n\n@Global()\n@Module({\n providers: [AlgoliaService],\n exports: [AlgoliaService],\n})\nexport class AlgoliaModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'algolia.ts'), `import { algoliasearch } from 'algoliasearch';\n\nconst client = algoliasearch(\n process.env.ALGOLIA_APP_ID || '',\n process.env.ALGOLIA_API_KEY || '',\n);\n\nexport async function search(indexName: string, query: string) {\n return client.searchSingleIndex({\n indexName,\n searchParams: { query },\n });\n}\n\nexport async function addObjects(indexName: string, objects: Record<string, any>[]) {\n return client.saveObjects({\n indexName,\n objects,\n });\n}\n\nexport async function deleteObject(indexName: string, objectId: string) {\n return client.deleteObject({\n indexName,\n objectID: objectId,\n });\n}\n\nexport default { search, addObjects, deleteObject };\n`);\n }\n\n dependencies['algoliasearch'] = deps.algoliasearch;\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 elasticsearchInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, dockerServices } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'search'));\n\n envEntries.push(\n { key: 'ELASTICSEARCH_NODE', value: 'http://localhost:9200', category: 'Elasticsearch' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'elasticsearch.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { Client } from '@elastic/elasticsearch';\n\n@Injectable()\nexport class ElasticsearchService {\n private client: Client;\n\n constructor(private configService: ConfigService) {\n this.client = new Client({\n node: this.configService.get('ELASTICSEARCH_NODE', 'http://localhost:9200'),\n });\n }\n\n async search(index: string, query: Record<string, any>) {\n return this.client.search({\n index,\n body: { query },\n });\n }\n\n async index(index: string, id: string, document: Record<string, any>) {\n return this.client.index({\n index,\n id,\n body: document,\n });\n }\n\n async delete(index: string, id: string) {\n return this.client.delete({\n index,\n id,\n });\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'elasticsearch.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { ElasticsearchService } from './elasticsearch.service';\n\n@Global()\n@Module({\n providers: [ElasticsearchService],\n exports: [ElasticsearchService],\n})\nexport class ElasticsearchModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'elasticsearch.ts'), `import { Client } from '@elastic/elasticsearch';\n\nconst client = new Client({\n node: process.env.ELASTICSEARCH_NODE || 'http://localhost:9200',\n});\n\nexport async function search(index: string, query: Record<string, any>) {\n return client.search({\n index,\n body: { query },\n });\n}\n\nexport async function index(indexName: string, id: string, document: Record<string, any>) {\n return client.index({\n index: indexName,\n id,\n body: document,\n });\n}\n\nexport async function deleteDoc(index: string, id: string) {\n return client.delete({\n index,\n id,\n });\n}\n\nexport default { search, index, deleteDoc };\n`);\n }\n\n dependencies['@elastic/elasticsearch'] = deps['@elastic/elasticsearch'];\n\n dockerServices.push(` elasticsearch:\\n image: docker.elastic.co/elasticsearch/elasticsearch:8.16.0\\n ports:\\n - \"9200:9200\"\\n - \"9300:9300\"\\n environment:\\n discovery.type: single-node\\n xpack.security.enabled: \"false\"\\n ES_JAVA_OPTS: \"-Xms512m -Xmx512m\"\\n volumes:\\n - elasticsearch_data:/usr/share/elasticsearch/data`);\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 typesenseInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies, dockerServices } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'search'));\n\n envEntries.push(\n { key: 'TYPESENSE_HOST', value: 'localhost', category: 'Typesense' },\n { key: 'TYPESENSE_PORT', value: '8108', category: 'Typesense' },\n { key: 'TYPESENSE_API_KEY', value: '', category: 'Typesense', comment: 'API Key do Typesense' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'typesense.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Typesense from 'typesense';\n\n@Injectable()\nexport class TypesenseService {\n private client: Typesense.Client;\n\n constructor(private configService: ConfigService) {\n this.client = new Typesense.Client({\n nodes: [{\n host: this.configService.get('TYPESENSE_HOST', 'localhost'),\n port: parseInt(this.configService.get('TYPESENSE_PORT', '8108'), 10),\n protocol: 'http',\n }],\n apiKey: this.configService.get('TYPESENSE_API_KEY', ''),\n });\n }\n\n async search(collection: string, query: string, queryBy: string) {\n return this.client.collections(collection).documents().search({\n q: query,\n query_by: queryBy,\n });\n }\n\n async addDocument(collection: string, document: Record<string, any>) {\n return this.client.collections(collection).documents().create(document);\n }\n\n async deleteDocument(collection: string, documentId: string) {\n return this.client.collections(collection).documents(documentId).delete();\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'typesense.module.ts'), `import { Global, Module } from '@nestjs/common';\nimport { TypesenseService } from './typesense.service';\n\n@Global()\n@Module({\n providers: [TypesenseService],\n exports: [TypesenseService],\n})\nexport class TypesenseModule {}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'search', 'typesense.ts'), `import Typesense from 'typesense';\n\nconst client = new Typesense.Client({\n nodes: [{\n host: process.env.TYPESENSE_HOST || 'localhost',\n port: parseInt(process.env.TYPESENSE_PORT || '8108', 10),\n protocol: 'http',\n }],\n apiKey: process.env.TYPESENSE_API_KEY || '',\n});\n\nexport async function search(collection: string, query: string, queryBy: string) {\n return client.collections(collection).documents().search({\n q: query,\n query_by: queryBy,\n });\n}\n\nexport async function addDocument(collection: string, document: Record<string, any>) {\n return client.collections(collection).documents().create(document);\n}\n\nexport async function deleteDocument(collection: string, documentId: string) {\n return client.collections(collection).documents(documentId).delete();\n}\n\nexport default { search, addDocument, deleteDocument };\n`);\n }\n\n dependencies['typesense'] = deps.typesense;\n\n dockerServices.push(` typesense:\\n image: typesense/typesense:27.1\\n ports:\\n - \"8108:8108\"\\n environment:\\n TYPESENSE_API_KEY: \\${TYPESENSE_API_KEY:-xyz}\\n TYPESENSE_DATA_DIR: /data\\n volumes:\\n - typesense_data:/data`);\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 graphqlInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'graphql'));\n\n if (config.backend === 'nestjs') {\n // Resolver (code-first)\n await writeFile(path.join(apiDir, 'src', 'graphql', 'app.resolver.ts'), `import { Query, Resolver, Mutation, Args, ObjectType, Field, ID } from '@nestjs/graphql';\n\n@ObjectType()\nexport class HealthResponse {\n @Field()\n status!: string;\n\n @Field()\n timestamp!: string;\n\n @Field()\n uptime!: number;\n}\n\n@ObjectType()\nexport class Message {\n @Field(() => ID)\n id!: string;\n\n @Field()\n content!: string;\n\n @Field()\n createdAt!: string;\n}\n\n@Resolver()\nexport class AppResolver {\n @Query(() => HealthResponse, { description: 'Health check da aplicacao' })\n health(): HealthResponse {\n return {\n status: 'ok',\n timestamp: new Date().toISOString(),\n uptime: process.uptime(),\n };\n }\n\n @Query(() => String, { description: 'Retorna uma saudacao' })\n hello(@Args('name', { defaultValue: 'World' }) name: string): string {\n return \\`Hello, \\${name}!\\`;\n }\n\n @Mutation(() => Message, { description: 'Cria uma mensagem de exemplo' })\n createMessage(@Args('content') content: string): Message {\n return {\n id: Date.now().toString(),\n content,\n createdAt: new Date().toISOString(),\n };\n }\n}\n`);\n\n // GraphQL Module\n await writeFile(path.join(apiDir, 'src', 'graphql', 'graphql.module.ts'), `import { Module } from '@nestjs/common';\nimport { GraphQLModule as NestGraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\nimport { AppResolver } from './app.resolver';\n\n@Module({\n imports: [\n NestGraphQLModule.forRoot<ApolloDriverConfig>({\n driver: ApolloDriver,\n autoSchemaFile: join(process.cwd(), 'src/graphql/schema.gql'),\n sortSchema: true,\n playground: process.env.NODE_ENV !== 'production',\n introspection: process.env.NODE_ENV !== 'production',\n }),\n ],\n providers: [AppResolver],\n})\nexport class GraphQLModule {}\n`);\n\n dependencies['@nestjs/graphql'] = deps['@nestjs/graphql'];\n dependencies['@nestjs/apollo'] = deps['@nestjs/apollo'];\n dependencies['@apollo/server'] = deps['@apollo/server'];\n dependencies['graphql'] = deps.graphql;\n\n } else {\n // Schema\n await writeFile(path.join(apiDir, 'src', 'graphql', 'schema.ts'), `export const typeDefs = \\`#graphql\n type Query {\n health: HealthResponse!\n hello(name: String = \"World\"): String!\n }\n\n type Mutation {\n createMessage(content: String!): Message!\n }\n\n type HealthResponse {\n status: String!\n timestamp: String!\n uptime: Float!\n }\n\n type Message {\n id: ID!\n content: String!\n createdAt: String!\n }\n\\`;\n`);\n\n // Resolvers\n await writeFile(path.join(apiDir, 'src', 'graphql', 'resolvers.ts'), `export const resolvers = {\n Query: {\n health: () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n uptime: process.uptime(),\n }),\n hello: (_: unknown, { name }: { name: string }) => {\n return \\`Hello, \\${name}!\\`;\n },\n },\n Mutation: {\n createMessage: (_: unknown, { content }: { content: string }) => ({\n id: Date.now().toString(),\n content,\n createdAt: new Date().toISOString(),\n }),\n },\n};\n`);\n\n // Server setup\n if (config.backend === 'express') {\n await writeFile(path.join(apiDir, 'src', 'graphql', 'apollo.ts'), `import { ApolloServer } from '@apollo/server';\nimport { expressMiddleware } from '@apollo/server/express4';\nimport { typeDefs } from './schema.js';\nimport { resolvers } from './resolvers.js';\nimport type { Express } from 'express';\n\n/**\n * Configura o Apollo Server com Express.\n *\n * Uso:\n * import { setupGraphQL } from './graphql/apollo.js';\n *\n * const app = express();\n * await setupGraphQL(app);\n */\nexport async function setupGraphQL(app: Express): Promise<void> {\n const server = new ApolloServer({\n typeDefs,\n resolvers,\n introspection: process.env.NODE_ENV !== 'production',\n });\n\n await server.start();\n\n app.use(\n '/graphql',\n expressMiddleware(server, {\n context: async ({ req }) => ({\n headers: req.headers,\n }),\n }) as any,\n );\n\n console.log('GraphQL disponivel em /graphql');\n}\n`);\n } else {\n // Fastify\n await writeFile(path.join(apiDir, 'src', 'graphql', 'apollo.ts'), `import { ApolloServer } from '@apollo/server';\nimport { fastifyApolloDrainPlugin, fastifyApolloHandler } from '@as-integrations/fastify';\nimport { typeDefs } from './schema.js';\nimport { resolvers } from './resolvers.js';\nimport type { FastifyInstance } from 'fastify';\n\n/**\n * Configura o Apollo Server com Fastify.\n *\n * Uso:\n * import { setupGraphQL } from './graphql/apollo.js';\n *\n * const app = Fastify();\n * await setupGraphQL(app);\n */\nexport async function setupGraphQL(app: FastifyInstance): Promise<void> {\n const server = new ApolloServer({\n typeDefs,\n resolvers,\n introspection: process.env.NODE_ENV !== 'production',\n plugins: [fastifyApolloDrainPlugin(app)],\n });\n\n await server.start();\n\n app.route({\n url: '/graphql',\n method: ['POST', 'GET'],\n handler: fastifyApolloHandler(server),\n });\n\n console.log('GraphQL disponivel em /graphql');\n}\n`);\n }\n\n dependencies['@apollo/server'] = deps['@apollo/server'];\n dependencies['graphql'] = deps.graphql;\n }\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\n\nexport const recaptchaInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'common', 'security'));\n\n envEntries.push(\n { key: 'RECAPTCHA_SITE_KEY', value: '', category: 'reCAPTCHA', comment: 'Obtenha em https://www.google.com/recaptcha' },\n { key: 'RECAPTCHA_SECRET_KEY', value: '', category: 'reCAPTCHA', comment: 'Obtenha em https://www.google.com/recaptcha' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'common', 'security', 'recaptcha.service.ts'), `import { Injectable, BadRequestException } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport axios from 'axios';\n\ninterface RecaptchaResponse {\n success: boolean;\n score?: number;\n action?: string;\n challenge_ts?: string;\n hostname?: string;\n 'error-codes'?: string[];\n}\n\n@Injectable()\nexport class RecaptchaService {\n private secretKey: string;\n\n constructor(private configService: ConfigService) {\n this.secretKey = this.configService.get('RECAPTCHA_SECRET_KEY', '');\n }\n\n /**\n * Verifica o token reCAPTCHA com a API do Google.\n * @param token - Token retornado pelo widget reCAPTCHA no frontend.\n * @param minScore - Score minimo para reCAPTCHA v3 (0.0 a 1.0). Padrao: 0.5.\n */\n async verify(token: string, minScore = 0.5): Promise<boolean> {\n if (!token) {\n throw new BadRequestException('Token reCAPTCHA nao fornecido');\n }\n\n const { data } = await axios.post<RecaptchaResponse>(\n 'https://www.google.com/recaptcha/api/siteverify',\n null,\n {\n params: {\n secret: this.secretKey,\n response: token,\n },\n },\n );\n\n if (!data.success) {\n throw new BadRequestException(\\`Falha na verificacao reCAPTCHA: \\${(data['error-codes'] || []).join(', ')}\\`);\n }\n\n // Para reCAPTCHA v3, verificar o score\n if (data.score !== undefined && data.score < minScore) {\n throw new BadRequestException(\\`Score reCAPTCHA muito baixo: \\${data.score}\\`);\n }\n\n return true;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'common', 'security', 'recaptcha.ts'), `import axios from 'axios';\n\ninterface RecaptchaResponse {\n success: boolean;\n score?: number;\n action?: string;\n challenge_ts?: string;\n hostname?: string;\n 'error-codes'?: string[];\n}\n\n/**\n * Verifica o token reCAPTCHA com a API do Google.\n *\n * Uso:\n * import { verifyRecaptcha } from './common/security/recaptcha.js';\n *\n * // Em uma rota:\n * const isValid = await verifyRecaptcha(req.body.recaptchaToken);\n *\n * @param token - Token retornado pelo widget reCAPTCHA no frontend.\n * @param minScore - Score minimo para reCAPTCHA v3 (0.0 a 1.0). Padrao: 0.5.\n */\nexport async function verifyRecaptcha(token: string, minScore = 0.5): Promise<boolean> {\n if (!token) {\n throw new Error('Token reCAPTCHA nao fornecido');\n }\n\n const secretKey = process.env.RECAPTCHA_SECRET_KEY || '';\n\n const { data } = await axios.post<RecaptchaResponse>(\n 'https://www.google.com/recaptcha/api/siteverify',\n null,\n {\n params: {\n secret: secretKey,\n response: token,\n },\n },\n );\n\n if (!data.success) {\n throw new Error(\\`Falha na verificacao reCAPTCHA: \\${(data['error-codes'] || []).join(', ')}\\`);\n }\n\n // Para reCAPTCHA v3, verificar o score\n if (data.score !== undefined && data.score < minScore) {\n throw new Error(\\`Score reCAPTCHA muito baixo: \\${data.score}\\`);\n }\n\n return true;\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\nexport const playwrightInstaller: InstallerFn = async (opts) => {\n const { projectDir, devDependencies, scripts } = opts;\n\n await ensureDir(path.join(projectDir, 'e2e'));\n\n // playwright.config.ts na raiz do projeto\n await writeFile(path.join(projectDir, 'playwright.config.ts'), `import { defineConfig, devices } from '@playwright/test';\n\n/**\n * Configuracao do Playwright para testes E2E.\n *\n * Documentacao: https://playwright.dev/docs/test-configuration\n */\nexport default defineConfig({\n testDir: './e2e',\n fullyParallel: true,\n forbidOnly: !!process.env.CI,\n retries: process.env.CI ? 2 : 0,\n workers: process.env.CI ? 1 : undefined,\n reporter: 'html',\n use: {\n baseURL: process.env.BASE_URL || 'http://localhost:3000',\n trace: 'on-first-retry',\n screenshot: 'only-on-failure',\n },\n projects: [\n {\n name: 'chromium',\n use: { ...devices['Desktop Chrome'] },\n },\n {\n name: 'firefox',\n use: { ...devices['Desktop Firefox'] },\n },\n {\n name: 'webkit',\n use: { ...devices['Desktop Safari'] },\n },\n {\n name: 'mobile-chrome',\n use: { ...devices['Pixel 5'] },\n },\n ],\n /* Descomente para iniciar o servidor automaticamente antes dos testes */\n // webServer: {\n // command: 'npm run dev',\n // url: 'http://localhost:3000',\n // reuseExistingServer: !process.env.CI,\n // },\n});\n`);\n\n // Teste de exemplo\n await writeFile(path.join(projectDir, 'e2e', 'home.spec.ts'), `import { test, expect } from '@playwright/test';\n\ntest.describe('Pagina Inicial', () => {\n test('deve carregar a pagina inicial', async ({ page }) => {\n await page.goto('/');\n\n // Verifica se a pagina carregou\n await expect(page).toHaveTitle(/.+/);\n });\n\n test('deve estar acessivel', async ({ page }) => {\n await page.goto('/');\n\n // Verifica se nao ha erros de console criticos\n const errors: string[] = [];\n page.on('console', (msg) => {\n if (msg.type() === 'error') {\n errors.push(msg.text());\n }\n });\n\n await page.waitForLoadState('networkidle');\n\n // Pagina nao deve ter erros de JavaScript\n expect(errors.length).toBe(0);\n });\n\n test('deve ter viewport responsivo', async ({ page }) => {\n await page.goto('/');\n\n // Verifica se o conteudo se adapta ao viewport\n const viewport = page.viewportSize();\n expect(viewport).toBeTruthy();\n });\n});\n`);\n\n devDependencies['@playwright/test'] = deps['@playwright/test'];\n\n scripts['test:e2e'] = 'playwright test';\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 inngestInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'jobs'));\n\n envEntries.push(\n { key: 'INNGEST_EVENT_KEY', value: '', category: 'Inngest' },\n { key: 'INNGEST_SIGNING_KEY', value: '', category: 'Inngest' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'jobs', 'inngest.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { Inngest } from 'inngest';\n\ninterface InngestEvent {\n name: string;\n data: Record<string, any>;\n}\n\n@Injectable()\nexport class InngestService {\n private client: Inngest;\n\n constructor(private configService: ConfigService) {\n this.client = new Inngest({\n id: 'my-app',\n eventKey: this.configService.get('INNGEST_EVENT_KEY', ''),\n });\n }\n\n /**\n * Envia um evento para o Inngest.\n */\n async send(event: InngestEvent): Promise<void> {\n await this.client.send(event);\n }\n\n /**\n * Envia multiplos eventos para o Inngest.\n */\n async sendBatch(events: InngestEvent[]): Promise<void> {\n await this.client.send(events);\n }\n\n /**\n * Retorna a instancia do client Inngest para criar funcoes.\n *\n * Uso:\n * const inngest = this.inngestService.getClient();\n * const myFunction = inngest.createFunction(\n * { id: 'my-function' },\n * { event: 'app/user.created' },\n * async ({ event, step }) => { ... }\n * );\n */\n getClient(): Inngest {\n return this.client;\n }\n}\n`);\n\n await writeFile(path.join(apiDir, 'src', 'jobs', 'example.function.ts'), `import { Inngest } from 'inngest';\n\nconst inngest = new Inngest({\n id: 'my-app',\n eventKey: process.env.INNGEST_EVENT_KEY || '',\n});\n\n/**\n * Exemplo de funcao Inngest que processa eventos de usuario criado.\n *\n * Registre esta funcao no serve do Inngest.\n */\nexport const onUserCreated = inngest.createFunction(\n { id: 'on-user-created', name: 'Processar novo usuario' },\n { event: 'app/user.created' },\n async ({ event, step }) => {\n // Step 1: Enviar email de boas-vindas\n await step.run('send-welcome-email', async () => {\n console.log(\\`Enviando email de boas-vindas para \\${event.data.email}\\`);\n // TODO: Implemente o envio de email\n });\n\n // Step 2: Criar registros iniciais\n await step.run('setup-initial-data', async () => {\n console.log(\\`Configurando dados iniciais para \\${event.data.userId}\\`);\n // TODO: Implemente a criacao de dados iniciais\n });\n\n return { success: true };\n },\n);\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'jobs', 'inngest.ts'), `import { Inngest } from 'inngest';\n\ninterface InngestEvent {\n name: string;\n data: Record<string, any>;\n}\n\nconst client = new Inngest({\n id: 'my-app',\n eventKey: process.env.INNGEST_EVENT_KEY || '',\n});\n\n/**\n * Envia um evento para o Inngest.\n *\n * Uso:\n * import { send, sendBatch, inngest } from './jobs/inngest.js';\n *\n * await send({ name: 'app/user.created', data: { userId: '123' } });\n */\nexport async function send(event: InngestEvent): Promise<void> {\n await client.send(event);\n}\n\n/**\n * Envia multiplos eventos para o Inngest.\n */\nexport async function sendBatch(events: InngestEvent[]): Promise<void> {\n await client.send(events);\n}\n\n/**\n * Instancia do client Inngest para criar funcoes.\n */\nexport const inngest = client;\n\nexport default { send, sendBatch, inngest };\n`);\n\n await writeFile(path.join(apiDir, 'src', 'jobs', 'example.function.ts'), `import { Inngest } from 'inngest';\n\nconst inngest = new Inngest({\n id: 'my-app',\n eventKey: process.env.INNGEST_EVENT_KEY || '',\n});\n\n/**\n * Exemplo de funcao Inngest que processa eventos de usuario criado.\n *\n * Registre esta funcao no serve do Inngest.\n */\nexport const onUserCreated = inngest.createFunction(\n { id: 'on-user-created', name: 'Processar novo usuario' },\n { event: 'app/user.created' },\n async ({ event, step }) => {\n // Step 1: Enviar email de boas-vindas\n await step.run('send-welcome-email', async () => {\n console.log(\\`Enviando email de boas-vindas para \\${event.data.email}\\`);\n // TODO: Implemente o envio de email\n });\n\n // Step 2: Criar registros iniciais\n await step.run('setup-initial-data', async () => {\n console.log(\\`Configurando dados iniciais para \\${event.data.userId}\\`);\n // TODO: Implemente a criacao de dados iniciais\n });\n\n return { success: true };\n },\n);\n`);\n }\n\n dependencies['inngest'] = deps.inngest;\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 puppeteerInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'pdf'));\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'pdf', 'puppeteer.service.ts'), `import { Injectable } from '@nestjs/common';\nimport puppeteer, { type PDFOptions, type ScreenshotOptions } from 'puppeteer';\n\n@Injectable()\nexport class PuppeteerService {\n /**\n * Converte HTML em PDF.\n * @param html - Conteudo HTML a ser convertido.\n * @param options - Opcoes adicionais do PDF.\n */\n async htmlToPdf(html: string, options?: PDFOptions): Promise<Buffer> {\n const browser = await puppeteer.launch({\n headless: true,\n args: ['--no-sandbox', '--disable-setuid-sandbox'],\n });\n\n try {\n const page = await browser.newPage();\n await page.setContent(html, { waitUntil: 'networkidle0' });\n\n const pdf = await page.pdf({\n format: 'A4',\n printBackground: true,\n margin: {\n top: '20mm',\n right: '15mm',\n bottom: '20mm',\n left: '15mm',\n },\n ...options,\n });\n\n return Buffer.from(pdf);\n } finally {\n await browser.close();\n }\n }\n\n /**\n * Captura um screenshot de uma URL.\n * @param url - URL para capturar.\n * @param options - Opcoes adicionais do screenshot.\n */\n async screenshot(url: string, options?: ScreenshotOptions): Promise<Buffer> {\n const browser = await puppeteer.launch({\n headless: true,\n args: ['--no-sandbox', '--disable-setuid-sandbox'],\n });\n\n try {\n const page = await browser.newPage();\n await page.setViewport({ width: 1280, height: 720 });\n await page.goto(url, { waitUntil: 'networkidle0' });\n\n const screenshot = await page.screenshot({\n type: 'png',\n fullPage: false,\n ...options,\n });\n\n return Buffer.from(screenshot);\n } finally {\n await browser.close();\n }\n }\n\n /**\n * Gera um PDF a partir de uma URL.\n * @param url - URL para converter em PDF.\n * @param options - Opcoes adicionais do PDF.\n */\n async urlToPdf(url: string, options?: PDFOptions): Promise<Buffer> {\n const browser = await puppeteer.launch({\n headless: true,\n args: ['--no-sandbox', '--disable-setuid-sandbox'],\n });\n\n try {\n const page = await browser.newPage();\n await page.goto(url, { waitUntil: 'networkidle0' });\n\n const pdf = await page.pdf({\n format: 'A4',\n printBackground: true,\n margin: {\n top: '20mm',\n right: '15mm',\n bottom: '20mm',\n left: '15mm',\n },\n ...options,\n });\n\n return Buffer.from(pdf);\n } finally {\n await browser.close();\n }\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'pdf', 'puppeteer.ts'), `import puppeteer, { type PDFOptions, type ScreenshotOptions } from 'puppeteer';\n\n/**\n * Converte HTML em PDF.\n *\n * Uso:\n * import { htmlToPdf } from './infra/pdf/puppeteer.js';\n *\n * const pdf = await htmlToPdf('<h1>Hello</h1>');\n * res.setHeader('Content-Type', 'application/pdf');\n * res.send(pdf);\n *\n * @param html - Conteudo HTML a ser convertido.\n * @param options - Opcoes adicionais do PDF.\n */\nexport async function htmlToPdf(html: string, options?: PDFOptions): Promise<Buffer> {\n const browser = await puppeteer.launch({\n headless: true,\n args: ['--no-sandbox', '--disable-setuid-sandbox'],\n });\n\n try {\n const page = await browser.newPage();\n await page.setContent(html, { waitUntil: 'networkidle0' });\n\n const pdf = await page.pdf({\n format: 'A4',\n printBackground: true,\n margin: {\n top: '20mm',\n right: '15mm',\n bottom: '20mm',\n left: '15mm',\n },\n ...options,\n });\n\n return Buffer.from(pdf);\n } finally {\n await browser.close();\n }\n}\n\n/**\n * Captura um screenshot de uma URL.\n * @param url - URL para capturar.\n * @param options - Opcoes adicionais do screenshot.\n */\nexport async function screenshot(url: string, options?: ScreenshotOptions): Promise<Buffer> {\n const browser = await puppeteer.launch({\n headless: true,\n args: ['--no-sandbox', '--disable-setuid-sandbox'],\n });\n\n try {\n const page = await browser.newPage();\n await page.setViewport({ width: 1280, height: 720 });\n await page.goto(url, { waitUntil: 'networkidle0' });\n\n const screenshot = await page.screenshot({\n type: 'png',\n fullPage: false,\n ...options,\n });\n\n return Buffer.from(screenshot);\n } finally {\n await browser.close();\n }\n}\n\n/**\n * Gera um PDF a partir de uma URL.\n * @param url - URL para converter em PDF.\n * @param options - Opcoes adicionais do PDF.\n */\nexport async function urlToPdf(url: string, options?: PDFOptions): Promise<Buffer> {\n const browser = await puppeteer.launch({\n headless: true,\n args: ['--no-sandbox', '--disable-setuid-sandbox'],\n });\n\n try {\n const page = await browser.newPage();\n await page.goto(url, { waitUntil: 'networkidle0' });\n\n const pdf = await page.pdf({\n format: 'A4',\n printBackground: true,\n margin: {\n top: '20mm',\n right: '15mm',\n bottom: '20mm',\n left: '15mm',\n },\n ...options,\n });\n\n return Buffer.from(pdf);\n } finally {\n await browser.close();\n }\n}\n\nexport default { htmlToPdf, screenshot, urlToPdf };\n`);\n }\n\n dependencies['puppeteer'] = deps.puppeteer;\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 strapiInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'cms'));\n\n envEntries.push(\n { key: 'STRAPI_URL', value: 'http://localhost:1337', category: 'Strapi' },\n { key: 'STRAPI_API_TOKEN', value: '', category: 'Strapi' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'cms', 'strapi.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport axios, { type AxiosInstance } from 'axios';\n\n@Injectable()\nexport class StrapiService {\n private client: AxiosInstance;\n\n constructor(private configService: ConfigService) {\n this.client = axios.create({\n baseURL: this.configService.get('STRAPI_URL', 'http://localhost:1337'),\n headers: {\n Authorization: \\`Bearer \\${this.configService.get('STRAPI_API_TOKEN', '')}\\`,\n 'Content-Type': 'application/json',\n },\n });\n }\n\n /**\n * Busca todos os registros de uma collection.\n * @param collection - Nome da collection no Strapi (ex: 'articles', 'products').\n * @param params - Parametros de query (filtros, paginacao, etc).\n */\n async find<T = any>(collection: string, params?: Record<string, any>): Promise<T[]> {\n const { data } = await this.client.get(\\`/api/\\${collection}\\`, { params });\n return data.data;\n }\n\n /**\n * Busca um registro especifico de uma collection.\n * @param collection - Nome da collection.\n * @param id - ID do registro.\n */\n async findOne<T = any>(collection: string, id: string | number): Promise<T> {\n const { data } = await this.client.get(\\`/api/\\${collection}/\\${id}\\`);\n return data.data;\n }\n\n /**\n * Cria um novo registro em uma collection.\n * @param collection - Nome da collection.\n * @param data - Dados do novo registro.\n */\n async create<T = any>(collection: string, body: Record<string, any>): Promise<T> {\n const { data } = await this.client.post(\\`/api/\\${collection}\\`, { data: body });\n return data.data;\n }\n\n /**\n * Atualiza um registro existente.\n * @param collection - Nome da collection.\n * @param id - ID do registro.\n * @param data - Dados a atualizar.\n */\n async update<T = any>(collection: string, id: string | number, body: Record<string, any>): Promise<T> {\n const { data } = await this.client.put(\\`/api/\\${collection}/\\${id}\\`, { data: body });\n return data.data;\n }\n\n /**\n * Remove um registro de uma collection.\n * @param collection - Nome da collection.\n * @param id - ID do registro.\n */\n async delete(collection: string, id: string | number): Promise<void> {\n await this.client.delete(\\`/api/\\${collection}/\\${id}\\`);\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'cms', 'strapi.service.ts'), `import axios, { type AxiosInstance } from 'axios';\n\nconst client: AxiosInstance = axios.create({\n baseURL: process.env.STRAPI_URL || 'http://localhost:1337',\n headers: {\n Authorization: \\`Bearer \\${process.env.STRAPI_API_TOKEN || ''}\\`,\n 'Content-Type': 'application/json',\n },\n});\n\n/**\n * Busca todos os registros de uma collection.\n *\n * Uso:\n * import { find, findOne, create } from './integrations/cms/strapi.service.js';\n *\n * const articles = await find('articles');\n * const article = await findOne('articles', 1);\n * const newArticle = await create('articles', { title: 'Hello' });\n *\n * @param collection - Nome da collection no Strapi (ex: 'articles', 'products').\n * @param params - Parametros de query (filtros, paginacao, etc).\n */\nexport async function find<T = any>(collection: string, params?: Record<string, any>): Promise<T[]> {\n const { data } = await client.get(\\`/api/\\${collection}\\`, { params });\n return data.data;\n}\n\n/**\n * Busca um registro especifico de uma collection.\n * @param collection - Nome da collection.\n * @param id - ID do registro.\n */\nexport async function findOne<T = any>(collection: string, id: string | number): Promise<T> {\n const { data } = await client.get(\\`/api/\\${collection}/\\${id}\\`);\n return data.data;\n}\n\n/**\n * Cria um novo registro em uma collection.\n * @param collection - Nome da collection.\n * @param body - Dados do novo registro.\n */\nexport async function create<T = any>(collection: string, body: Record<string, any>): Promise<T> {\n const { data } = await client.post(\\`/api/\\${collection}\\`, { data: body });\n return data.data;\n}\n\n/**\n * Atualiza um registro existente.\n * @param collection - Nome da collection.\n * @param id - ID do registro.\n * @param body - Dados a atualizar.\n */\nexport async function update<T = any>(collection: string, id: string | number, body: Record<string, any>): Promise<T> {\n const { data } = await client.put(\\`/api/\\${collection}/\\${id}\\`, { data: body });\n return data.data;\n}\n\n/**\n * Remove um registro de uma collection.\n * @param collection - Nome da collection.\n * @param id - ID do registro.\n */\nexport async function remove(collection: string, id: string | number): Promise<void> {\n await client.delete(\\`/api/\\${collection}/\\${id}\\`);\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 sanityInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'cms'));\n\n envEntries.push(\n { key: 'SANITY_PROJECT_ID', value: '', category: 'Sanity' },\n { key: 'SANITY_DATASET', value: 'production', category: 'Sanity' },\n { key: 'SANITY_API_TOKEN', value: '', category: 'Sanity' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'cms', 'sanity.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { createClient, type SanityClient } from '@sanity/client';\n\n@Injectable()\nexport class SanityService {\n private client: SanityClient;\n\n constructor(private configService: ConfigService) {\n this.client = createClient({\n projectId: this.configService.get('SANITY_PROJECT_ID', ''),\n dataset: this.configService.get('SANITY_DATASET', 'production'),\n token: this.configService.get('SANITY_API_TOKEN', ''),\n apiVersion: '2024-01-01',\n useCdn: process.env.NODE_ENV === 'production',\n });\n }\n\n /**\n * Executa uma query GROQ no Sanity.\n * @param groq - Query GROQ.\n * @param params - Parametros da query.\n *\n * Exemplo:\n * const posts = await sanityService.query('*[_type == \"post\"]{ title, slug }');\n */\n async query<T = any>(groq: string, params?: Record<string, any>): Promise<T> {\n return this.client.fetch<T>(groq, params || {});\n }\n\n /**\n * Cria um novo documento no Sanity.\n * @param type - Tipo do documento (ex: 'post', 'author').\n * @param data - Dados do documento.\n */\n async create<T = any>(type: string, data: Record<string, any>): Promise<T> {\n return this.client.create({\n _type: type,\n ...data,\n }) as Promise<T>;\n }\n\n /**\n * Atualiza um documento existente no Sanity.\n * @param documentId - ID do documento.\n * @param data - Campos a atualizar.\n */\n async update<T = any>(documentId: string, data: Record<string, any>): Promise<T> {\n return this.client.patch(documentId).set(data).commit() as Promise<T>;\n }\n\n /**\n * Remove um documento do Sanity.\n * @param documentId - ID do documento.\n */\n async delete(documentId: string): Promise<void> {\n await this.client.delete(documentId);\n }\n\n /**\n * Retorna a instancia do client Sanity para operacoes avancadas.\n */\n getClient(): SanityClient {\n return this.client;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'cms', 'sanity.service.ts'), `import { createClient, type SanityClient } from '@sanity/client';\n\nconst client: SanityClient = createClient({\n projectId: process.env.SANITY_PROJECT_ID || '',\n dataset: process.env.SANITY_DATASET || 'production',\n token: process.env.SANITY_API_TOKEN || '',\n apiVersion: '2024-01-01',\n useCdn: process.env.NODE_ENV === 'production',\n});\n\n/**\n * Executa uma query GROQ no Sanity.\n *\n * Uso:\n * import { query, create } from './integrations/cms/sanity.service.js';\n *\n * const posts = await query('*[_type == \"post\"]{ title, slug }');\n * const newPost = await create('post', { title: 'Hello World' });\n *\n * @param groq - Query GROQ.\n * @param params - Parametros da query.\n */\nexport async function query<T = any>(groq: string, params?: Record<string, any>): Promise<T> {\n return client.fetch<T>(groq, params || {});\n}\n\n/**\n * Cria um novo documento no Sanity.\n * @param type - Tipo do documento (ex: 'post', 'author').\n * @param data - Dados do documento.\n */\nexport async function create<T = any>(type: string, data: Record<string, any>): Promise<T> {\n return client.create({\n _type: type,\n ...data,\n }) as Promise<T>;\n}\n\n/**\n * Atualiza um documento existente no Sanity.\n * @param documentId - ID do documento.\n * @param data - Campos a atualizar.\n */\nexport async function update<T = any>(documentId: string, data: Record<string, any>): Promise<T> {\n return client.patch(documentId).set(data).commit() as Promise<T>;\n}\n\n/**\n * Remove um documento do Sanity.\n * @param documentId - ID do documento.\n */\nexport async function remove(documentId: string): Promise<void> {\n await client.delete(documentId);\n}\n\n/**\n * Retorna a instancia do client Sanity para operacoes avancadas.\n */\nexport function getClient(): SanityClient {\n return client;\n}\n`);\n }\n\n dependencies['@sanity/client'] = deps['@sanity/client'];\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 paddleInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'paddle'));\n\n envEntries.push(\n { key: 'PADDLE_API_KEY', value: '', category: 'Paddle', comment: 'Obtenha em https://vendors.paddle.com' },\n { key: 'PADDLE_WEBHOOK_SECRET', value: '', category: 'Paddle' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'paddle', 'paddle.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { Paddle } from '@paddle/paddle-node-sdk';\n\n@Injectable()\nexport class PaddleService {\n private paddle: Paddle;\n\n constructor(private configService: ConfigService) {\n this.paddle = new Paddle(this.configService.get('PADDLE_API_KEY', ''));\n }\n\n async createCheckout(params: {\n items: Array<{ priceId: string; quantity: number }>;\n customerEmail?: string;\n successUrl?: string;\n }) {\n return this.paddle.transactions.create({\n items: params.items.map((i) => ({\n price_id: i.priceId,\n quantity: i.quantity,\n })),\n checkout: {\n url: params.successUrl,\n },\n customer_id: undefined,\n });\n }\n\n async getSubscription(subscriptionId: string) {\n return this.paddle.subscriptions.get(subscriptionId);\n }\n\n async cancelSubscription(subscriptionId: string) {\n return this.paddle.subscriptions.cancel(subscriptionId, {\n effective_from: 'next_billing_period',\n });\n }\n\n verifyWebhook(rawBody: string, signature: string): boolean {\n const secret = this.configService.get('PADDLE_WEBHOOK_SECRET', '');\n // Implement webhook signature verification\n return !!secret && !!rawBody && !!signature;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'paddle', 'paddle.service.ts'), `import { Paddle } from '@paddle/paddle-node-sdk';\n\nconst paddle = new Paddle(process.env.PADDLE_API_KEY || '');\n\nexport async function createCheckout(params: {\n items: Array<{ priceId: string; quantity: number }>;\n customerEmail?: string;\n successUrl?: string;\n}) {\n return paddle.transactions.create({\n items: params.items.map((i) => ({\n price_id: i.priceId,\n quantity: i.quantity,\n })),\n checkout: {\n url: params.successUrl,\n },\n customer_id: undefined,\n });\n}\n\nexport async function getSubscription(subscriptionId: string) {\n return paddle.subscriptions.get(subscriptionId);\n}\n\nexport async function cancelSubscription(subscriptionId: string) {\n return paddle.subscriptions.cancel(subscriptionId, {\n effective_from: 'next_billing_period',\n });\n}\n\nexport function verifyWebhook(rawBody: string, signature: string): boolean {\n const secret = process.env.PADDLE_WEBHOOK_SECRET || '';\n // Implement webhook signature verification\n return !!secret && !!rawBody && !!signature;\n}\n`);\n }\n\n dependencies['@paddle/paddle-node-sdk'] = deps['@paddle/paddle-node-sdk'];\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 lemonSqueezyInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'lemonsqueezy'));\n\n envEntries.push(\n { key: 'LEMONSQUEEZY_API_KEY', value: '', category: 'Lemon Squeezy', comment: 'Obtenha em https://app.lemonsqueezy.com' },\n { key: 'LEMONSQUEEZY_STORE_ID', value: '', category: 'Lemon Squeezy' },\n { key: 'LEMONSQUEEZY_WEBHOOK_SECRET', value: '', category: 'Lemon Squeezy' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'lemonsqueezy', 'lemonsqueezy.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport {\n lemonSqueezySetup,\n createCheckout,\n getSubscription,\n cancelSubscription,\n listProducts,\n} from '@lemonsqueezy/lemonsqueezy.js';\n\n@Injectable()\nexport class LemonSqueezyService {\n private storeId: string;\n\n constructor(private configService: ConfigService) {\n lemonSqueezySetup({\n apiKey: this.configService.get('LEMONSQUEEZY_API_KEY', ''),\n });\n this.storeId = this.configService.get('LEMONSQUEEZY_STORE_ID', '');\n }\n\n async createCheckout(params: {\n variantId: number;\n customerEmail?: string;\n customData?: Record<string, string>;\n }) {\n return createCheckout(this.storeId, params.variantId, {\n checkoutData: {\n email: params.customerEmail,\n custom: params.customData ? Object.entries(params.customData) as any : undefined,\n },\n });\n }\n\n async getSubscription(subscriptionId: string) {\n return getSubscription(subscriptionId);\n }\n\n async cancelSubscription(subscriptionId: string) {\n return cancelSubscription(subscriptionId);\n }\n\n async listProducts() {\n return listProducts({ filter: { storeId: this.storeId } });\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'lemonsqueezy', 'lemonsqueezy.service.ts'), `import {\n lemonSqueezySetup,\n createCheckout,\n getSubscription as getSubscriptionApi,\n cancelSubscription as cancelSubscriptionApi,\n listProducts,\n} from '@lemonsqueezy/lemonsqueezy.js';\n\nlemonSqueezySetup({\n apiKey: process.env.LEMONSQUEEZY_API_KEY || '',\n});\n\nconst storeId = process.env.LEMONSQUEEZY_STORE_ID || '';\n\nexport async function createLemonCheckout(params: {\n variantId: number;\n customerEmail?: string;\n customData?: Record<string, string>;\n}) {\n return createCheckout(storeId, params.variantId, {\n checkoutData: {\n email: params.customerEmail,\n custom: params.customData ? Object.entries(params.customData) as any : undefined,\n },\n });\n}\n\nexport async function getSubscription(subscriptionId: string) {\n return getSubscriptionApi(subscriptionId);\n}\n\nexport async function cancelSubscription(subscriptionId: string) {\n return cancelSubscriptionApi(subscriptionId);\n}\n\nexport async function getAllProducts() {\n return listProducts({ filter: { storeId } });\n}\n`);\n }\n\n dependencies['@lemonsqueezy/lemonsqueezy.js'] = deps['@lemonsqueezy/lemonsqueezy.js'];\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 pagSeguroInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'pagseguro'));\n\n envEntries.push(\n { key: 'PAGSEGURO_TOKEN', value: '', category: 'PagSeguro', comment: 'Obtenha em https://pagseguro.uol.com.br' },\n { key: 'PAGSEGURO_EMAIL', value: '', category: 'PagSeguro' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'pagseguro', 'pagseguro.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport axios, { AxiosInstance } from 'axios';\n\n@Injectable()\nexport class PagSeguroService {\n private client: AxiosInstance;\n private token: string;\n private email: string;\n\n constructor(private configService: ConfigService) {\n this.token = this.configService.get('PAGSEGURO_TOKEN', '');\n this.email = this.configService.get('PAGSEGURO_EMAIL', '');\n this.client = axios.create({\n baseURL: 'https://ws.pagseguro.uol.com.br',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: \\`Bearer \\${this.token}\\`,\n },\n });\n }\n\n async createPayment(params: {\n description: string;\n amount: number;\n referenceId: string;\n customerName: string;\n customerEmail: string;\n customerCpf: string;\n }) {\n const { data } = await this.client.post('/orders', {\n reference_id: params.referenceId,\n customer: {\n name: params.customerName,\n email: params.customerEmail,\n tax_id: params.customerCpf,\n },\n items: [\n {\n reference_id: params.referenceId,\n name: params.description,\n quantity: 1,\n unit_amount: Math.round(params.amount * 100),\n },\n ],\n });\n return data;\n }\n\n async getPayment(orderId: string) {\n const { data } = await this.client.get(\\`/orders/\\${orderId}\\`);\n return data;\n }\n\n async createPixPayment(params: {\n amount: number;\n description: string;\n referenceId: string;\n }) {\n const { data } = await this.client.post('/orders', {\n reference_id: params.referenceId,\n items: [\n {\n reference_id: params.referenceId,\n name: params.description,\n quantity: 1,\n unit_amount: Math.round(params.amount * 100),\n },\n ],\n qr_codes: [\n {\n amount: { value: Math.round(params.amount * 100) },\n },\n ],\n });\n return data;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'pagseguro', 'pagseguro.service.ts'), `import axios from 'axios';\n\nconst client = axios.create({\n baseURL: 'https://ws.pagseguro.uol.com.br',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: \\`Bearer \\${process.env.PAGSEGURO_TOKEN || ''}\\`,\n },\n});\n\nexport async function createPayment(params: {\n description: string;\n amount: number;\n referenceId: string;\n customerName: string;\n customerEmail: string;\n customerCpf: string;\n}) {\n const { data } = await client.post('/orders', {\n reference_id: params.referenceId,\n customer: {\n name: params.customerName,\n email: params.customerEmail,\n tax_id: params.customerCpf,\n },\n items: [\n {\n reference_id: params.referenceId,\n name: params.description,\n quantity: 1,\n unit_amount: Math.round(params.amount * 100),\n },\n ],\n });\n return data;\n}\n\nexport async function getPayment(orderId: string) {\n const { data } = await client.get(\\`/orders/\\${orderId}\\`);\n return data;\n}\n\nexport async function createPixPayment(params: {\n amount: number;\n description: string;\n referenceId: string;\n}) {\n const { data } = await client.post('/orders', {\n reference_id: params.referenceId,\n items: [\n {\n reference_id: params.referenceId,\n name: params.description,\n quantity: 1,\n unit_amount: Math.round(params.amount * 100),\n },\n ],\n qr_codes: [\n {\n amount: { value: Math.round(params.amount * 100) },\n },\n ],\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 asaasInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'asaas'));\n\n envEntries.push(\n { key: 'ASAAS_API_KEY', value: '', category: 'Asaas', comment: 'Obtenha em https://www.asaas.com' },\n { key: 'ASAAS_ENVIRONMENT', value: 'sandbox', category: 'Asaas' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'asaas', 'asaas.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport axios, { AxiosInstance } from 'axios';\n\n@Injectable()\nexport class AsaasService {\n private client: AxiosInstance;\n\n constructor(private configService: ConfigService) {\n const env = this.configService.get('ASAAS_ENVIRONMENT', 'sandbox');\n const baseURL =\n env === 'production'\n ? 'https://api.asaas.com/v3'\n : 'https://sandbox.asaas.com/api/v3';\n\n this.client = axios.create({\n baseURL,\n headers: {\n 'Content-Type': 'application/json',\n access_token: this.configService.get('ASAAS_API_KEY', ''),\n },\n });\n }\n\n async createCharge(params: {\n customer: string;\n billingType: 'BOLETO' | 'PIX' | 'CREDIT_CARD';\n value: number;\n dueDate: string;\n description?: string;\n }) {\n const { data } = await this.client.post('/payments', {\n customer: params.customer,\n billingType: params.billingType,\n value: params.value,\n dueDate: params.dueDate,\n description: params.description,\n });\n return data;\n }\n\n async getCharge(chargeId: string) {\n const { data } = await this.client.get(\\`/payments/\\${chargeId}\\`);\n return data;\n }\n\n async createCustomer(params: {\n name: string;\n cpfCnpj: string;\n email?: string;\n phone?: string;\n }) {\n const { data } = await this.client.post('/customers', params);\n return data;\n }\n\n async getPixQrCode(chargeId: string) {\n const { data } = await this.client.get(\\`/payments/\\${chargeId}/pixQrCode\\`);\n return data;\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'asaas', 'asaas.service.ts'), `import axios from 'axios';\n\nconst env = process.env.ASAAS_ENVIRONMENT || 'sandbox';\nconst baseURL =\n env === 'production'\n ? 'https://api.asaas.com/v3'\n : 'https://sandbox.asaas.com/api/v3';\n\nconst client = axios.create({\n baseURL,\n headers: {\n 'Content-Type': 'application/json',\n access_token: process.env.ASAAS_API_KEY || '',\n },\n});\n\nexport async function createCharge(params: {\n customer: string;\n billingType: 'BOLETO' | 'PIX' | 'CREDIT_CARD';\n value: number;\n dueDate: string;\n description?: string;\n}) {\n const { data } = await client.post('/payments', {\n customer: params.customer,\n billingType: params.billingType,\n value: params.value,\n dueDate: params.dueDate,\n description: params.description,\n });\n return data;\n}\n\nexport async function getCharge(chargeId: string) {\n const { data } = await client.get(\\`/payments/\\${chargeId}\\`);\n return data;\n}\n\nexport async function createCustomer(params: {\n name: string;\n cpfCnpj: string;\n email?: string;\n phone?: string;\n}) {\n const { data } = await client.post('/customers', params);\n return data;\n}\n\nexport async function getPixQrCode(chargeId: string) {\n const { data } = await client.get(\\`/payments/\\${chargeId}/pixQrCode\\`);\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 anthropicInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'anthropic'));\n\n envEntries.push(\n { key: 'ANTHROPIC_API_KEY', value: '', category: 'Anthropic', comment: 'Obtenha em https://console.anthropic.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'anthropic', 'anthropic.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Anthropic from '@anthropic-ai/sdk';\n\n@Injectable()\nexport class AnthropicService {\n private client: Anthropic;\n\n constructor(private configService: ConfigService) {\n this.client = new Anthropic({\n apiKey: this.configService.get('ANTHROPIC_API_KEY', ''),\n });\n }\n\n async chat(messages: Anthropic.MessageParam[]) {\n const response = await this.client.messages.create({\n model: 'claude-sonnet-4-20250514',\n max_tokens: 4096,\n messages,\n });\n const textBlock = response.content.find((block) => block.type === 'text');\n return textBlock?.type === 'text' ? textBlock.text : '';\n }\n\n async completion(prompt: string) {\n return this.chat([{ role: 'user', content: prompt }]);\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'anthropic', 'anthropic.service.ts'), `import Anthropic from '@anthropic-ai/sdk';\n\nconst client = new Anthropic({\n apiKey: process.env.ANTHROPIC_API_KEY || '',\n});\n\nexport async function chat(messages: Anthropic.MessageParam[]) {\n const response = await client.messages.create({\n model: 'claude-sonnet-4-20250514',\n max_tokens: 4096,\n messages,\n });\n const textBlock = response.content.find((block) => block.type === 'text');\n return textBlock?.type === 'text' ? textBlock.text : '';\n}\n\nexport async function completion(prompt: string) {\n return chat([{ role: 'user', content: prompt }]);\n}\n`);\n }\n\n dependencies['@anthropic-ai/sdk'] = deps['@anthropic-ai/sdk'];\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 googleGeminiInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'gemini'));\n\n envEntries.push(\n { key: 'GOOGLE_AI_API_KEY', value: '', category: 'Google Gemini', comment: 'Obtenha em https://aistudio.google.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'gemini', 'gemini.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { GoogleGenerativeAI, Content } from '@google/generative-ai';\n\n@Injectable()\nexport class GeminiService {\n private genAI: GoogleGenerativeAI;\n\n constructor(private configService: ConfigService) {\n this.genAI = new GoogleGenerativeAI(\n this.configService.get('GOOGLE_AI_API_KEY', ''),\n );\n }\n\n async generateContent(prompt: string) {\n const model = this.genAI.getGenerativeModel({ model: 'gemini-pro' });\n const result = await model.generateContent(prompt);\n return result.response.text();\n }\n\n async chat(messages: Array<{ role: 'user' | 'model'; content: string }>) {\n const model = this.genAI.getGenerativeModel({ model: 'gemini-pro' });\n const history: Content[] = messages.slice(0, -1).map((m) => ({\n role: m.role,\n parts: [{ text: m.content }],\n }));\n\n const chat = model.startChat({ history });\n const lastMessage = messages[messages.length - 1];\n const result = await chat.sendMessage(lastMessage?.content ?? '');\n return result.response.text();\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'gemini', 'gemini.service.ts'), `import { GoogleGenerativeAI, Content } from '@google/generative-ai';\n\nconst genAI = new GoogleGenerativeAI(process.env.GOOGLE_AI_API_KEY || '');\n\nexport async function generateContent(prompt: string) {\n const model = genAI.getGenerativeModel({ model: 'gemini-pro' });\n const result = await model.generateContent(prompt);\n return result.response.text();\n}\n\nexport async function chat(messages: Array<{ role: 'user' | 'model'; content: string }>) {\n const model = genAI.getGenerativeModel({ model: 'gemini-pro' });\n const history: Content[] = messages.slice(0, -1).map((m) => ({\n role: m.role,\n parts: [{ text: m.content }],\n }));\n\n const chatSession = model.startChat({ history });\n const lastMessage = messages[messages.length - 1];\n const result = await chatSession.sendMessage(lastMessage?.content ?? '');\n return result.response.text();\n}\n`);\n }\n\n dependencies['@google/generative-ai'] = deps['@google/generative-ai'];\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 langchainInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'langchain'));\n\n envEntries.push(\n { key: 'OPENAI_API_KEY', value: '', category: 'LangChain', comment: 'Obtenha em https://platform.openai.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'langchain', 'langchain.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';\nimport { HumanMessage, SystemMessage } from 'langchain/schema';\nimport { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';\n\n@Injectable()\nexport class LangchainService {\n private model: ChatOpenAI;\n private embeddings: OpenAIEmbeddings;\n\n constructor(private configService: ConfigService) {\n this.model = new ChatOpenAI({\n openAIApiKey: this.configService.get('OPENAI_API_KEY', ''),\n modelName: 'gpt-4o',\n temperature: 0.7,\n });\n\n this.embeddings = new OpenAIEmbeddings({\n openAIApiKey: this.configService.get('OPENAI_API_KEY', ''),\n });\n }\n\n /**\n * Envia uma mensagem para o modelo e retorna a resposta.\n */\n async chat(prompt: string): Promise<string> {\n const response = await this.model.invoke([\n new HumanMessage(prompt),\n ]);\n return response.content as string;\n }\n\n /**\n * Realiza uma consulta RAG (Retrieval-Augmented Generation).\n * Recebe uma pergunta e o contexto relevante ja recuperado.\n */\n async ragQuery(question: string, context: string): Promise<string> {\n const response = await this.model.invoke([\n new SystemMessage(\n \\`Voce e um assistente que responde perguntas com base no contexto fornecido.\nSe a resposta nao estiver no contexto, diga que nao sabe.\n\nContexto:\n\\${context}\\`,\n ),\n new HumanMessage(question),\n ]);\n return response.content as string;\n }\n\n /**\n * Divide um texto em chunks para processamento.\n */\n async splitText(text: string, chunkSize = 1000, chunkOverlap = 200): Promise<string[]> {\n const splitter = new RecursiveCharacterTextSplitter({\n chunkSize,\n chunkOverlap,\n });\n const docs = await splitter.createDocuments([text]);\n return docs.map((doc) => doc.pageContent);\n }\n\n /**\n * Gera embeddings para um texto.\n */\n async getEmbeddings(text: string): Promise<number[]> {\n return this.embeddings.embedQuery(text);\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'langchain', 'langchain.service.ts'), `import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';\nimport { HumanMessage, SystemMessage } from 'langchain/schema';\nimport { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';\n\nconst model = new ChatOpenAI({\n openAIApiKey: process.env.OPENAI_API_KEY || '',\n modelName: 'gpt-4o',\n temperature: 0.7,\n});\n\nconst embeddings = new OpenAIEmbeddings({\n openAIApiKey: process.env.OPENAI_API_KEY || '',\n});\n\n/**\n * Envia uma mensagem para o modelo e retorna a resposta.\n */\nexport async function chat(prompt: string): Promise<string> {\n const response = await model.invoke([\n new HumanMessage(prompt),\n ]);\n return response.content as string;\n}\n\n/**\n * Realiza uma consulta RAG (Retrieval-Augmented Generation).\n * Recebe uma pergunta e o contexto relevante ja recuperado.\n */\nexport async function ragQuery(question: string, context: string): Promise<string> {\n const response = await model.invoke([\n new SystemMessage(\n \\`Voce e um assistente que responde perguntas com base no contexto fornecido.\nSe a resposta nao estiver no contexto, diga que nao sabe.\n\nContexto:\n\\${context}\\`,\n ),\n new HumanMessage(question),\n ]);\n return response.content as string;\n}\n\n/**\n * Divide um texto em chunks para processamento.\n */\nexport async function splitText(text: string, chunkSize = 1000, chunkOverlap = 200): Promise<string[]> {\n const splitter = new RecursiveCharacterTextSplitter({\n chunkSize,\n chunkOverlap,\n });\n const docs = await splitter.createDocuments([text]);\n return docs.map((doc) => doc.pageContent);\n}\n\n/**\n * Gera embeddings para um texto.\n */\nexport async function getEmbeddings(text: string): Promise<number[]> {\n return embeddings.embedQuery(text);\n}\n`);\n }\n\n dependencies['langchain'] = deps.langchain;\n dependencies['@langchain/openai'] = deps['@langchain/openai'];\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 slackWebhookInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'slack'));\n\n envEntries.push(\n { key: 'SLACK_WEBHOOK_URL', value: '', category: 'Slack', comment: 'Obtenha em https://api.slack.com/apps' },\n { key: 'SLACK_BOT_TOKEN', value: '', category: 'Slack', comment: 'Obtenha em https://api.slack.com/apps' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'slack', 'slack.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { WebClient } from '@slack/web-api';\n\n@Injectable()\nexport class SlackService {\n private client: WebClient;\n private readonly webhookUrl: string;\n\n constructor(private configService: ConfigService) {\n this.client = new WebClient(this.configService.get('SLACK_BOT_TOKEN', ''));\n this.webhookUrl = this.configService.get('SLACK_WEBHOOK_URL', '');\n }\n\n async sendMessage(channel: string, text: string) {\n return this.client.chat.postMessage({\n channel,\n text,\n });\n }\n\n async sendWebhook(text: string) {\n return fetch(this.webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ text }),\n });\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'slack', 'slack.service.ts'), `import { WebClient } from '@slack/web-api';\n\nconst client = new WebClient(process.env.SLACK_BOT_TOKEN || '');\nconst WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL || '';\n\nexport async function sendMessage(channel: string, text: string) {\n return client.chat.postMessage({\n channel,\n text,\n });\n}\n\nexport async function sendWebhook(text: string) {\n return fetch(WEBHOOK_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ text }),\n });\n}\n`);\n }\n\n dependencies['@slack/web-api'] = deps['@slack/web-api'];\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 discordWebhookInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'discord'));\n\n envEntries.push(\n { key: 'DISCORD_WEBHOOK_URL', value: '', category: 'Discord', comment: 'Obtenha em https://discord.com/developers/applications' },\n { key: 'DISCORD_BOT_TOKEN', value: '', category: 'Discord', comment: 'Obtenha em https://discord.com/developers/applications' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'discord', 'discord.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { Client, GatewayIntentBits, TextChannel } from 'discord.js';\n\n@Injectable()\nexport class DiscordService {\n private client: Client;\n private readonly webhookUrl: string;\n\n constructor(private configService: ConfigService) {\n this.client = new Client({\n intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],\n });\n this.webhookUrl = this.configService.get('DISCORD_WEBHOOK_URL', '');\n\n const token = this.configService.get('DISCORD_BOT_TOKEN', '');\n if (token) {\n this.client.login(token);\n }\n }\n\n async sendWebhook(content: string) {\n return fetch(this.webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ content }),\n });\n }\n\n async sendMessage(channelId: string, content: string) {\n const channel = await this.client.channels.fetch(channelId);\n if (channel && channel instanceof TextChannel) {\n return channel.send(content);\n }\n throw new Error(\\`Canal \\${channelId} nao encontrado ou nao e um canal de texto\\`);\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'discord', 'discord.service.ts'), `import { Client, GatewayIntentBits, TextChannel } from 'discord.js';\n\nconst client = new Client({\n intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],\n});\nconst WEBHOOK_URL = process.env.DISCORD_WEBHOOK_URL || '';\n\nconst token = process.env.DISCORD_BOT_TOKEN || '';\nif (token) {\n client.login(token);\n}\n\nexport async function sendWebhook(content: string) {\n return fetch(WEBHOOK_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ content }),\n });\n}\n\nexport async function sendMessage(channelId: string, content: string) {\n const channel = await client.channels.fetch(channelId);\n if (channel && channel instanceof TextChannel) {\n return channel.send(content);\n }\n throw new Error(\\`Canal \\${channelId} nao encontrado ou nao e um canal de texto\\`);\n}\n`);\n }\n\n dependencies['discord.js'] = deps['discord.js'];\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 firebaseFcmInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'firebase'));\n\n envEntries.push(\n { key: 'FIREBASE_PROJECT_ID', value: '', category: 'Firebase', comment: 'Obtenha em https://console.firebase.google.com' },\n { key: 'FIREBASE_PRIVATE_KEY', value: '', category: 'Firebase', comment: 'Obtenha em https://console.firebase.google.com' },\n { key: 'FIREBASE_CLIENT_EMAIL', value: '', category: 'Firebase', comment: 'Obtenha em https://console.firebase.google.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'firebase', 'firebase.service.ts'), `import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport * as admin from 'firebase-admin';\n\n@Injectable()\nexport class FirebaseService implements OnModuleInit {\n private app: admin.app.App;\n\n constructor(private configService: ConfigService) {}\n\n onModuleInit() {\n this.app = admin.initializeApp({\n credential: admin.credential.cert({\n projectId: this.configService.get('FIREBASE_PROJECT_ID', ''),\n privateKey: this.configService.get('FIREBASE_PRIVATE_KEY', '').replace(/\\\\\\\\n/g, '\\\\n'),\n clientEmail: this.configService.get('FIREBASE_CLIENT_EMAIL', ''),\n }),\n });\n }\n\n async sendPush(token: string, title: string, body: string) {\n return this.app.messaging().send({\n token,\n notification: { title, body },\n });\n }\n\n async sendToTopic(topic: string, title: string, body: string) {\n return this.app.messaging().send({\n topic,\n notification: { title, body },\n });\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'firebase', 'firebase.service.ts'), `import * as admin from 'firebase-admin';\n\nconst app = admin.initializeApp({\n credential: admin.credential.cert({\n projectId: process.env.FIREBASE_PROJECT_ID || '',\n privateKey: (process.env.FIREBASE_PRIVATE_KEY || '').replace(/\\\\\\\\n/g, '\\\\n'),\n clientEmail: process.env.FIREBASE_CLIENT_EMAIL || '',\n }),\n});\n\nexport async function sendPush(token: string, title: string, body: string) {\n return app.messaging().send({\n token,\n notification: { title, body },\n });\n}\n\nexport async function sendToTopic(topic: string, title: string, body: string) {\n return app.messaging().send({\n topic,\n notification: { title, body },\n });\n}\n`);\n }\n\n dependencies['firebase-admin'] = deps['firebase-admin'];\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 oneSignalInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'onesignal'));\n\n envEntries.push(\n { key: 'ONESIGNAL_APP_ID', value: '', category: 'OneSignal', comment: 'Obtenha em https://onesignal.com' },\n { key: 'ONESIGNAL_API_KEY', value: '', category: 'OneSignal', comment: 'Obtenha em https://onesignal.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'onesignal', 'onesignal.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport * as OneSignal from 'onesignal-node';\n\n@Injectable()\nexport class OneSignalService {\n private client: OneSignal.Client;\n\n constructor(private configService: ConfigService) {\n this.client = new OneSignal.Client(\n this.configService.get('ONESIGNAL_APP_ID', ''),\n this.configService.get('ONESIGNAL_API_KEY', ''),\n );\n }\n\n async sendNotification(playerIds: string[], message: string) {\n const notification = {\n contents: { en: message },\n include_player_ids: playerIds,\n };\n return this.client.createNotification(notification);\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'onesignal', 'onesignal.service.ts'), `import * as OneSignal from 'onesignal-node';\n\nconst client = new OneSignal.Client(\n process.env.ONESIGNAL_APP_ID || '',\n process.env.ONESIGNAL_API_KEY || '',\n);\n\nexport async function sendNotification(playerIds: string[], message: string) {\n const notification = {\n contents: { en: message },\n include_player_ids: playerIds,\n };\n return client.createNotification(notification);\n}\n`);\n }\n\n dependencies['onesignal-node'] = deps['onesignal-node'];\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 mapboxInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'integrations', 'mapbox'));\n\n envEntries.push(\n { key: 'MAPBOX_ACCESS_TOKEN', value: '', category: 'Mapbox', comment: 'Obtenha em https://mapbox.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'mapbox', 'mapbox.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport MapboxSdk from '@mapbox/mapbox-sdk';\nimport MapboxGeocoding from '@mapbox/mapbox-sdk/services/geocoding';\nimport MapboxDirections from '@mapbox/mapbox-sdk/services/directions';\n\n@Injectable()\nexport class MapboxService {\n private geocodingClient: ReturnType<typeof MapboxGeocoding>;\n private directionsClient: ReturnType<typeof MapboxDirections>;\n\n constructor(private configService: ConfigService) {\n const baseClient = MapboxSdk({\n accessToken: this.configService.get('MAPBOX_ACCESS_TOKEN', ''),\n });\n\n this.geocodingClient = MapboxGeocoding(baseClient);\n this.directionsClient = MapboxDirections(baseClient);\n }\n\n /**\n * Geocodifica um endereco e retorna as coordenadas.\n */\n async geocode(address: string) {\n const response = await this.geocodingClient\n .forwardGeocode({ query: address, limit: 1 })\n .send();\n\n const feature = response.body.features[0];\n if (!feature) return null;\n\n return {\n latitude: feature.center[1],\n longitude: feature.center[0],\n placeName: feature.place_name,\n };\n }\n\n /**\n * Geocodificacao reversa: coordenadas para endereco.\n */\n async reverseGeocode(lat: number, lng: number) {\n const response = await this.geocodingClient\n .reverseGeocode({ query: [lng, lat], limit: 1 })\n .send();\n\n const feature = response.body.features[0];\n if (!feature) return null;\n\n return {\n placeName: feature.place_name,\n latitude: lat,\n longitude: lng,\n };\n }\n\n /**\n * Obtem direcoes entre dois pontos.\n * origin e destination devem ser no formato [longitude, latitude].\n */\n async getDirections(origin: [number, number], destination: [number, number]) {\n const response = await this.directionsClient\n .getDirections({\n profile: 'driving',\n waypoints: [\n { coordinates: origin },\n { coordinates: destination },\n ],\n geometries: 'geojson',\n })\n .send();\n\n const route = response.body.routes[0];\n if (!route) return null;\n\n return {\n distance: route.distance,\n duration: route.duration,\n geometry: route.geometry,\n };\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'integrations', 'mapbox', 'mapbox.service.ts'), `import MapboxSdk from '@mapbox/mapbox-sdk';\nimport MapboxGeocoding from '@mapbox/mapbox-sdk/services/geocoding';\nimport MapboxDirections from '@mapbox/mapbox-sdk/services/directions';\n\nconst baseClient = MapboxSdk({\n accessToken: process.env.MAPBOX_ACCESS_TOKEN || '',\n});\n\nconst geocodingClient = MapboxGeocoding(baseClient);\nconst directionsClient = MapboxDirections(baseClient);\n\n/**\n * Geocodifica um endereco e retorna as coordenadas.\n */\nexport async function geocode(address: string) {\n const response = await geocodingClient\n .forwardGeocode({ query: address, limit: 1 })\n .send();\n\n const feature = response.body.features[0];\n if (!feature) return null;\n\n return {\n latitude: feature.center[1],\n longitude: feature.center[0],\n placeName: feature.place_name,\n };\n}\n\n/**\n * Geocodificacao reversa: coordenadas para endereco.\n */\nexport async function reverseGeocode(lat: number, lng: number) {\n const response = await geocodingClient\n .reverseGeocode({ query: [lng, lat], limit: 1 })\n .send();\n\n const feature = response.body.features[0];\n if (!feature) return null;\n\n return {\n placeName: feature.place_name,\n latitude: lat,\n longitude: lng,\n };\n}\n\n/**\n * Obtem direcoes entre dois pontos.\n * origin e destination devem ser no formato [longitude, latitude].\n */\nexport async function getDirections(origin: [number, number], destination: [number, number]) {\n const response = await directionsClient\n .getDirections({\n profile: 'driving',\n waypoints: [\n { coordinates: origin },\n { coordinates: destination },\n ],\n geometries: 'geojson',\n })\n .send();\n\n const route = response.body.routes[0];\n if (!route) return null;\n\n return {\n distance: route.distance,\n duration: route.duration,\n geometry: route.geometry,\n };\n}\n`);\n }\n\n dependencies['@mapbox/mapbox-sdk'] = deps['@mapbox/mapbox-sdk'];\n};\n","import path from 'path';\nimport type { InstallerFn } from '../../types/installers.js';\nimport { ensureDir, writeFile } from '../../helpers/filesystem.js';\n\nexport const hotjarInstaller: InstallerFn = async (opts) => {\n const { config, webDir, envEntries } = opts;\n\n await ensureDir(path.join(webDir, 'src', 'analytics'));\n\n envEntries.push(\n { key: 'NEXT_PUBLIC_HOTJAR_ID', value: '', category: 'Hotjar', comment: 'Obtenha em https://www.hotjar.com' },\n );\n\n if (config.frontend === 'nextjs') {\n await writeFile(path.join(webDir, 'src', 'analytics', 'Hotjar.tsx'), `'use client';\n\nimport { useEffect } from 'react';\n\n/**\n * Componente Hotjar para Next.js.\n *\n * Uso no layout principal (app/layout.tsx):\n *\n * import { HotjarProvider } from '@/analytics/Hotjar';\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html>\n * <body>\n * {children}\n * <HotjarProvider />\n * </body>\n * </html>\n * );\n * }\n */\nexport function HotjarProvider() {\n const hotjarId = process.env.NEXT_PUBLIC_HOTJAR_ID;\n\n useEffect(() => {\n if (!hotjarId || typeof window === 'undefined') return;\n\n const script = document.createElement('script');\n script.innerHTML = \\`\n (function(h,o,t,j,a,r){\n h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n h._hjSettings={hjid:\\${hotjarId},hjsv:6};\n a=o.getElementsByTagName('head')[0];\n r=o.createElement('script');r.async=1;\n r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n a.appendChild(r);\n })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n \\`;\n document.head.appendChild(script);\n\n return () => {\n document.head.removeChild(script);\n };\n }, [hotjarId]);\n\n return null;\n}\n\n/**\n * Envia um evento personalizado para o Hotjar.\n */\nexport function trackHotjarEvent(eventName: string) {\n if (typeof window !== 'undefined' && window.hj) {\n window.hj('event', eventName);\n }\n}\n\n/**\n * Identifica o usuario no Hotjar.\n */\nexport function identifyHotjarUser(userId: string, attributes?: Record<string, string | number | boolean>) {\n if (typeof window !== 'undefined' && window.hj) {\n window.hj('identify', userId, attributes || {});\n }\n}\n\n// Declaracao global para o Hotjar\ndeclare global {\n interface Window {\n hj: (...args: any[]) => void;\n _hjSettings: { hjid: number; hjsv: number };\n }\n}\n`);\n } else {\n await writeFile(path.join(webDir, 'src', 'analytics', 'hotjar.ts'), `/**\n * Hotjar - Integracao para SPA.\n *\n * Uso:\n * import { initHotjar, trackHotjarEvent, identifyHotjarUser } from './analytics/hotjar';\n *\n * // Na inicializacao do app:\n * initHotjar();\n *\n * // Para eventos customizados:\n * trackHotjarEvent('signup_clicked');\n *\n * // Para identificar usuario:\n * identifyHotjarUser('user-123', { plan: 'pro' });\n */\n\nconst HOTJAR_ID = import.meta.env.VITE_HOTJAR_ID || '';\n\n/**\n * Injeta o script do Hotjar no documento.\n */\nexport function initHotjar(): void {\n if (!HOTJAR_ID || typeof document === 'undefined') return;\n\n const script = document.createElement('script');\n script.innerHTML = \\`\n (function(h,o,t,j,a,r){\n h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n h._hjSettings={hjid:\\${HOTJAR_ID},hjsv:6};\n a=o.getElementsByTagName('head')[0];\n r=o.createElement('script');r.async=1;\n r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n a.appendChild(r);\n })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n \\`;\n document.head.appendChild(script);\n}\n\n/**\n * Envia um evento personalizado para o Hotjar.\n */\nexport function trackHotjarEvent(eventName: string): void {\n if (typeof window !== 'undefined' && window.hj) {\n window.hj('event', eventName);\n }\n}\n\n/**\n * Identifica o usuario no Hotjar.\n */\nexport function identifyHotjarUser(userId: string, attributes?: Record<string, string | number | boolean>): void {\n if (typeof window !== 'undefined' && window.hj) {\n window.hj('identify', userId, attributes || {});\n }\n}\n\n// Declaracao global para o Hotjar\ndeclare global {\n interface Window {\n hj: (...args: any[]) => void;\n _hjSettings: { hjid: number; hjsv: number };\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\nexport const cloudinaryInstaller: 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: 'CLOUDINARY_CLOUD_NAME', value: '', category: 'Cloudinary' },\n { key: 'CLOUDINARY_API_KEY', value: '', category: 'Cloudinary' },\n { key: 'CLOUDINARY_API_SECRET', value: '', category: 'Cloudinary' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'cloudinary.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { v2 as cloudinary, type UploadApiResponse } from 'cloudinary';\n\n@Injectable()\nexport class CloudinaryService {\n constructor(private configService: ConfigService) {\n cloudinary.config({\n cloud_name: this.configService.get('CLOUDINARY_CLOUD_NAME', ''),\n api_key: this.configService.get('CLOUDINARY_API_KEY', ''),\n api_secret: this.configService.get('CLOUDINARY_API_SECRET', ''),\n });\n }\n\n /**\n * Faz upload de um arquivo para o Cloudinary.\n * @param file - Buffer ou caminho do arquivo.\n * @param folder - Pasta no Cloudinary (opcional).\n */\n async upload(file: Buffer | string, folder?: string): Promise<UploadApiResponse> {\n return new Promise((resolve, reject) => {\n const uploadOptions: Record<string, any> = {};\n if (folder) uploadOptions.folder = folder;\n\n if (Buffer.isBuffer(file)) {\n const stream = cloudinary.uploader.upload_stream(uploadOptions, (error, result) => {\n if (error || !result) return reject(error);\n resolve(result);\n });\n stream.end(file);\n } else {\n cloudinary.uploader.upload(file, uploadOptions, (error, result) => {\n if (error || !result) return reject(error);\n resolve(result);\n });\n }\n });\n }\n\n /**\n * Retorna a URL publica de um recurso pelo publicId.\n */\n getUrl(publicId: string, options?: { width?: number; height?: number; crop?: string }): string {\n return cloudinary.url(publicId, {\n secure: true,\n ...options,\n });\n }\n\n /**\n * Remove um recurso do Cloudinary pelo publicId.\n */\n async destroy(publicId: string): Promise<{ result: string }> {\n return cloudinary.uploader.destroy(publicId);\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'cloudinary.service.ts'), `import { v2 as cloudinary, type UploadApiResponse } from 'cloudinary';\n\ncloudinary.config({\n cloud_name: process.env.CLOUDINARY_CLOUD_NAME || '',\n api_key: process.env.CLOUDINARY_API_KEY || '',\n api_secret: process.env.CLOUDINARY_API_SECRET || '',\n});\n\n/**\n * Faz upload de um arquivo para o Cloudinary.\n * @param file - Buffer ou caminho do arquivo.\n * @param folder - Pasta no Cloudinary (opcional).\n */\nexport async function upload(file: Buffer | string, folder?: string): Promise<UploadApiResponse> {\n return new Promise((resolve, reject) => {\n const uploadOptions: Record<string, any> = {};\n if (folder) uploadOptions.folder = folder;\n\n if (Buffer.isBuffer(file)) {\n const stream = cloudinary.uploader.upload_stream(uploadOptions, (error, result) => {\n if (error || !result) return reject(error);\n resolve(result);\n });\n stream.end(file);\n } else {\n cloudinary.uploader.upload(file, uploadOptions, (error, result) => {\n if (error || !result) return reject(error);\n resolve(result);\n });\n }\n });\n}\n\n/**\n * Retorna a URL publica de um recurso pelo publicId.\n */\nexport function getUrl(publicId: string, options?: { width?: number; height?: number; crop?: string }): string {\n return cloudinary.url(publicId, {\n secure: true,\n ...options,\n });\n}\n\n/**\n * Remove um recurso do Cloudinary pelo publicId.\n */\nexport async function destroy(publicId: string): Promise<{ result: string }> {\n return cloudinary.uploader.destroy(publicId);\n}\n`);\n }\n\n dependencies['cloudinary'] = deps.cloudinary;\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 uploadThingInstaller: 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: 'UPLOADTHING_SECRET', value: '', category: 'UploadThing' },\n { key: 'UPLOADTHING_APP_ID', value: '', category: 'UploadThing' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'upload.service.ts'), `import { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { UTApi } from 'uploadthing/server';\n\n@Injectable()\nexport class UploadService {\n private utapi: UTApi;\n\n constructor(private configService: ConfigService) {\n this.utapi = new UTApi({\n apiKey: this.configService.get('UPLOADTHING_SECRET', ''),\n });\n }\n\n /**\n * Faz upload de arquivos usando o UploadThing.\n */\n async uploadFiles(files: File[]): Promise<any[]> {\n const response = await this.utapi.uploadFiles(files);\n return response;\n }\n\n /**\n * Retorna a URL de um arquivo pelo key.\n */\n async getFileUrl(fileKey: string): Promise<string> {\n const urls = await this.utapi.getFileUrls([fileKey]);\n return urls.data[0]?.url ?? '';\n }\n\n /**\n * Remove um arquivo pelo key.\n */\n async deleteFile(fileKey: string): Promise<void> {\n await this.utapi.deleteFiles([fileKey]);\n }\n\n /**\n * Lista os arquivos enviados.\n */\n async listFiles() {\n return this.utapi.listFiles();\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'storage', 'upload.service.ts'), `import { UTApi } from 'uploadthing/server';\n\nconst utapi = new UTApi({\n apiKey: process.env.UPLOADTHING_SECRET || '',\n});\n\n/**\n * Faz upload de arquivos usando o UploadThing.\n */\nexport async function uploadFiles(files: File[]): Promise<any[]> {\n const response = await utapi.uploadFiles(files);\n return response;\n}\n\n/**\n * Retorna a URL de um arquivo pelo key.\n */\nexport async function getFileUrl(fileKey: string): Promise<string> {\n const urls = await utapi.getFileUrls([fileKey]);\n return urls.data[0]?.url ?? '';\n}\n\n/**\n * Remove um arquivo pelo key.\n */\nexport async function deleteFile(fileKey: string): Promise<void> {\n await utapi.deleteFiles([fileKey]);\n}\n\n/**\n * Lista os arquivos enviados.\n */\nexport async function listFiles() {\n return utapi.listFiles();\n}\n`);\n }\n\n dependencies['uploadthing'] = deps.uploadthing;\n};\n","import { InstallerFn } from '../../types/installer.js';\n\nexport const googleMapsInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n dependencies['@googlemaps/google-maps-services-js'] = '^3.4.0';\n\n envEntries.push(\n '# Google Maps',\n 'GOOGLE_MAPS_API_KEY=your-google-maps-api-key',\n ''\n );\n\n const isNest = config.backend === 'nestjs';\n\n if (isNest) {\n const serviceContent = `import { Injectable } from '@nestjs/common';\nimport { Client, GeocodeResult, PlaceDetailsResult } from '@googlemaps/google-maps-services-js';\n\n@Injectable()\nexport class GoogleMapsService {\n private client: Client;\n\n constructor() {\n this.client = new Client({});\n }\n\n async geocode(address: string): Promise<GeocodeResult[]> {\n const response = await this.client.geocode({\n params: {\n address,\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data.results;\n }\n\n async reverseGeocode(lat: number, lng: number): Promise<GeocodeResult[]> {\n const response = await this.client.reverseGeocode({\n params: {\n latlng: { lat, lng },\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data.results;\n }\n\n async placeDetails(placeId: string) {\n const response = await this.client.placeDetails({\n params: {\n place_id: placeId,\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data.result;\n }\n\n async placesNearby(lat: number, lng: number, radius: number = 1000) {\n const response = await this.client.placesNearby({\n params: {\n location: { lat, lng },\n radius,\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data.results;\n }\n\n async directions(origin: string, destination: string) {\n const response = await this.client.directions({\n params: {\n origin,\n destination,\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data.routes;\n }\n\n async distanceMatrix(origins: string[], destinations: string[]) {\n const response = await this.client.distancematrix({\n params: {\n origins,\n destinations,\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data;\n }\n}\n`;\n\n const moduleContent = `import { Module } from '@nestjs/common';\nimport { GoogleMapsService } from './google-maps.service';\n\n@Module({\n providers: [GoogleMapsService],\n exports: [GoogleMapsService],\n})\nexport class GoogleMapsModule {}\n`;\n\n await opts.writeFile(`${apiDir}/src/integrations/google-maps.service.ts`, serviceContent);\n await opts.writeFile(`${apiDir}/src/integrations/google-maps.module.ts`, moduleContent);\n } else {\n const serviceContent = `import { Client } from '@googlemaps/google-maps-services-js';\n\nconst client = new Client({});\n\nexport async function geocode(address: string) {\n const response = await client.geocode({\n params: {\n address,\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data.results;\n}\n\nexport async function reverseGeocode(lat: number, lng: number) {\n const response = await client.reverseGeocode({\n params: {\n latlng: { lat, lng },\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data.results;\n}\n\nexport async function placeDetails(placeId: string) {\n const response = await client.placeDetails({\n params: {\n place_id: placeId,\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data.result;\n}\n\nexport async function placesNearby(lat: number, lng: number, radius: number = 1000) {\n const response = await client.placesNearby({\n params: {\n location: { lat, lng },\n radius,\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data.results;\n}\n\nexport async function getDirections(origin: string, destination: string) {\n const response = await client.directions({\n params: {\n origin,\n destination,\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n });\n return response.data.routes;\n}\n`;\n\n await opts.writeFile(`${apiDir}/src/integrations/google-maps.ts`, serviceContent);\n }\n};\n","import { InstallerFn } from '../../types/installer.js';\n\nexport const supabaseInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, webDir, envEntries, dependencies } = opts;\n\n dependencies['@supabase/supabase-js'] = '^2.45.0';\n\n envEntries.push(\n '# Supabase',\n 'SUPABASE_URL=https://your-project.supabase.co',\n 'SUPABASE_ANON_KEY=your-anon-key',\n 'SUPABASE_SERVICE_ROLE_KEY=your-service-role-key',\n ''\n );\n\n const isNest = config.backend === 'nestjs';\n\n if (isNest) {\n const serviceContent = `import { Injectable } from '@nestjs/common';\nimport { createClient, SupabaseClient } from '@supabase/supabase-js';\n\n@Injectable()\nexport class SupabaseService {\n private client: SupabaseClient;\n\n constructor() {\n this.client = createClient(\n process.env.SUPABASE_URL!,\n process.env.SUPABASE_SERVICE_ROLE_KEY!,\n );\n }\n\n getClient(): SupabaseClient {\n return this.client;\n }\n\n async uploadFile(bucket: string, path: string, file: Buffer, contentType: string) {\n const { data, error } = await this.client.storage\n .from(bucket)\n .upload(path, file, { contentType });\n if (error) throw error;\n return data;\n }\n\n async getPublicUrl(bucket: string, path: string) {\n const { data } = this.client.storage.from(bucket).getPublicUrl(path);\n return data.publicUrl;\n }\n\n async from(table: string) {\n return this.client.from(table);\n }\n}\n`;\n\n const moduleContent = `import { Module, Global } from '@nestjs/common';\nimport { SupabaseService } from './supabase.service';\n\n@Global()\n@Module({\n providers: [SupabaseService],\n exports: [SupabaseService],\n})\nexport class SupabaseModule {}\n`;\n\n await opts.writeFile(`${apiDir}/src/integrations/supabase.service.ts`, serviceContent);\n await opts.writeFile(`${apiDir}/src/integrations/supabase.module.ts`, moduleContent);\n } else {\n const serviceContent = `import { createClient, SupabaseClient } from '@supabase/supabase-js';\n\nlet supabase: SupabaseClient;\n\nexport function getSupabaseClient(): SupabaseClient {\n if (!supabase) {\n supabase = createClient(\n process.env.SUPABASE_URL!,\n process.env.SUPABASE_SERVICE_ROLE_KEY!,\n );\n }\n return supabase;\n}\n\nexport async function uploadFile(bucket: string, path: string, file: Buffer, contentType: string) {\n const client = getSupabaseClient();\n const { data, error } = await client.storage\n .from(bucket)\n .upload(path, file, { contentType });\n if (error) throw error;\n return data;\n}\n\nexport async function getPublicUrl(bucket: string, path: string) {\n const client = getSupabaseClient();\n const { data } = client.storage.from(bucket).getPublicUrl(path);\n return data.publicUrl;\n}\n`;\n\n await opts.writeFile(`${apiDir}/src/integrations/supabase.ts`, serviceContent);\n }\n\n // Frontend client\n if (config.frontend === 'nextjs' || config.frontend === 'react') {\n const clientContent = `import { createClient } from '@supabase/supabase-js';\n\nexport const supabase = createClient(\n process.env.NEXT_PUBLIC_SUPABASE_URL!,\n process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,\n);\n`;\n await opts.writeFile(`${webDir}/src/lib/supabase.ts`, clientContent);\n\n envEntries.push(\n '# Supabase (Frontend)',\n 'NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co',\n 'NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key',\n ''\n );\n }\n};\n","import { InstallerFn } from '../../types/installer.js';\n\nexport const firebaseInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, webDir, envEntries, dependencies } = opts;\n\n dependencies['firebase-admin'] = '^12.6.0';\n\n envEntries.push(\n '# Firebase',\n 'FIREBASE_PROJECT_ID=your-project-id',\n 'FIREBASE_CLIENT_EMAIL=your-client-email@your-project.iam.gserviceaccount.com',\n 'FIREBASE_PRIVATE_KEY=\"-----BEGIN PRIVATE KEY-----\\\\nYOUR_KEY\\\\n-----END PRIVATE KEY-----\"',\n 'FIREBASE_STORAGE_BUCKET=your-project.appspot.com',\n ''\n );\n\n const isNest = config.backend === 'nestjs';\n\n if (isNest) {\n const serviceContent = `import { Injectable, OnModuleInit } from '@nestjs/common';\nimport * as admin from 'firebase-admin';\n\n@Injectable()\nexport class FirebaseService implements OnModuleInit {\n private app: admin.app.App;\n\n onModuleInit() {\n this.app = admin.initializeApp({\n credential: admin.credential.cert({\n projectId: process.env.FIREBASE_PROJECT_ID,\n clientEmail: process.env.FIREBASE_CLIENT_EMAIL,\n privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\\\\\\\n/g, '\\\\n'),\n }),\n storageBucket: process.env.FIREBASE_STORAGE_BUCKET,\n });\n }\n\n getAuth() {\n return this.app.auth();\n }\n\n getFirestore() {\n return this.app.firestore();\n }\n\n getStorage() {\n return this.app.storage();\n }\n\n getMessaging() {\n return this.app.messaging();\n }\n\n async verifyIdToken(token: string) {\n return this.app.auth().verifyIdToken(token);\n }\n}\n`;\n\n const moduleContent = `import { Module, Global } from '@nestjs/common';\nimport { FirebaseService } from './firebase.service';\n\n@Global()\n@Module({\n providers: [FirebaseService],\n exports: [FirebaseService],\n})\nexport class FirebaseModule {}\n`;\n\n await opts.writeFile(`${apiDir}/src/integrations/firebase.service.ts`, serviceContent);\n await opts.writeFile(`${apiDir}/src/integrations/firebase.module.ts`, moduleContent);\n } else {\n const serviceContent = `import * as admin from 'firebase-admin';\n\nlet app: admin.app.App;\n\nexport function initFirebase(): admin.app.App {\n if (!app) {\n app = admin.initializeApp({\n credential: admin.credential.cert({\n projectId: process.env.FIREBASE_PROJECT_ID,\n clientEmail: process.env.FIREBASE_CLIENT_EMAIL,\n privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\\\\\\\n/g, '\\\\n'),\n }),\n storageBucket: process.env.FIREBASE_STORAGE_BUCKET,\n });\n }\n return app;\n}\n\nexport function getAuth() {\n return initFirebase().auth();\n}\n\nexport function getFirestore() {\n return initFirebase().firestore();\n}\n\nexport function getStorage() {\n return initFirebase().storage();\n}\n\nexport function getMessaging() {\n return initFirebase().messaging();\n}\n\nexport async function verifyIdToken(token: string) {\n return initFirebase().auth().verifyIdToken(token);\n}\n`;\n\n await opts.writeFile(`${apiDir}/src/integrations/firebase.ts`, serviceContent);\n }\n\n // Frontend SDK\n if (config.frontend === 'nextjs' || config.frontend === 'react') {\n dependencies['firebase'] = '^10.14.0';\n\n const clientContent = `import { initializeApp } from 'firebase/app';\nimport { getAuth } from 'firebase/auth';\nimport { getFirestore } from 'firebase/firestore';\nimport { getStorage } from 'firebase/storage';\n\nconst firebaseConfig = {\n apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,\n authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,\n projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,\n storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,\n messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,\n appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,\n};\n\nexport const app = initializeApp(firebaseConfig);\nexport const auth = getAuth(app);\nexport const db = getFirestore(app);\nexport const storage = getStorage(app);\n`;\n\n await opts.writeFile(`${webDir}/src/lib/firebase.ts`, clientContent);\n\n envEntries.push(\n '# Firebase (Frontend)',\n 'NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key',\n 'NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com',\n 'NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id',\n 'NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.appspot.com',\n 'NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-sender-id',\n 'NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id',\n ''\n );\n }\n};\n","import { InstallerFn } from '../../types/installer.js';\n\nexport const neonDbInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n dependencies['@neondatabase/serverless'] = '^0.9.5';\n\n envEntries.push(\n '# Neon Database',\n 'NEON_DATABASE_URL=postgres://user:password@ep-xxx.us-east-2.aws.neon.tech/dbname?sslmode=require',\n ''\n );\n\n const isNest = config.backend === 'nestjs';\n\n if (isNest) {\n const serviceContent = `import { Injectable } from '@nestjs/common';\nimport { neon, neonConfig, NeonQueryFunction } from '@neondatabase/serverless';\n\n@Injectable()\nexport class NeonDbService {\n private sql: NeonQueryFunction<false, false>;\n\n constructor() {\n neonConfig.fetchConnectionCache = true;\n this.sql = neon(process.env.NEON_DATABASE_URL!);\n }\n\n async query<T = any>(query: string, params?: any[]): Promise<T[]> {\n const result = await this.sql(query, params);\n return result as T[];\n }\n\n async queryOne<T = any>(query: string, params?: any[]): Promise<T | null> {\n const result = await this.sql(query, params);\n return (result[0] as T) || null;\n }\n\n async execute(query: string, params?: any[]): Promise<void> {\n await this.sql(query, params);\n }\n}\n`;\n\n const moduleContent = `import { Module, Global } from '@nestjs/common';\nimport { NeonDbService } from './neon-db.service';\n\n@Global()\n@Module({\n providers: [NeonDbService],\n exports: [NeonDbService],\n})\nexport class NeonDbModule {}\n`;\n\n await opts.writeFile(`${apiDir}/src/database/neon-db.service.ts`, serviceContent);\n await opts.writeFile(`${apiDir}/src/database/neon-db.module.ts`, moduleContent);\n } else {\n const serviceContent = `import { neon, neonConfig, NeonQueryFunction } from '@neondatabase/serverless';\n\nneonConfig.fetchConnectionCache = true;\n\nlet sql: NeonQueryFunction<false, false>;\n\nexport function getNeonClient() {\n if (!sql) {\n sql = neon(process.env.NEON_DATABASE_URL!);\n }\n return sql;\n}\n\nexport async function query<T = any>(queryStr: string, params?: any[]): Promise<T[]> {\n const client = getNeonClient();\n const result = await client(queryStr, params);\n return result as T[];\n}\n\nexport async function queryOne<T = any>(queryStr: string, params?: any[]): Promise<T | null> {\n const client = getNeonClient();\n const result = await client(queryStr, params);\n return (result[0] as T) || null;\n}\n`;\n\n await opts.writeFile(`${apiDir}/src/database/neon-db.ts`, serviceContent);\n }\n};\n","import { InstallerFn } from '../../types/installer.js';\n\nexport const upstashRedisInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n dependencies['@upstash/redis'] = '^1.34.3';\n\n envEntries.push(\n '# Upstash Redis',\n 'UPSTASH_REDIS_REST_URL=https://your-endpoint.upstash.io',\n 'UPSTASH_REDIS_REST_TOKEN=your-token',\n ''\n );\n\n const isNest = config.backend === 'nestjs';\n\n if (isNest) {\n const serviceContent = `import { Injectable } from '@nestjs/common';\nimport { Redis } from '@upstash/redis';\n\n@Injectable()\nexport class UpstashRedisService {\n private redis: Redis;\n\n constructor() {\n this.redis = new Redis({\n url: process.env.UPSTASH_REDIS_REST_URL!,\n token: process.env.UPSTASH_REDIS_REST_TOKEN!,\n });\n }\n\n getClient(): Redis {\n return this.redis;\n }\n\n async get<T = any>(key: string): Promise<T | null> {\n return this.redis.get<T>(key);\n }\n\n async set(key: string, value: any, ttlSeconds?: number) {\n if (ttlSeconds) {\n return this.redis.set(key, value, { ex: ttlSeconds });\n }\n return this.redis.set(key, value);\n }\n\n async del(key: string) {\n return this.redis.del(key);\n }\n\n async incr(key: string) {\n return this.redis.incr(key);\n }\n\n async hset(key: string, field: string, value: any) {\n return this.redis.hset(key, { [field]: value });\n }\n\n async hget<T = any>(key: string, field: string): Promise<T | null> {\n return this.redis.hget<T>(key, field);\n }\n\n async hgetall<T = Record<string, any>>(key: string): Promise<T | null> {\n return this.redis.hgetall<T>(key);\n }\n}\n`;\n\n const moduleContent = `import { Module, Global } from '@nestjs/common';\nimport { UpstashRedisService } from './upstash-redis.service';\n\n@Global()\n@Module({\n providers: [UpstashRedisService],\n exports: [UpstashRedisService],\n})\nexport class UpstashRedisModule {}\n`;\n\n await opts.writeFile(`${apiDir}/src/infra/upstash-redis.service.ts`, serviceContent);\n await opts.writeFile(`${apiDir}/src/infra/upstash-redis.module.ts`, moduleContent);\n } else {\n const serviceContent = `import { Redis } from '@upstash/redis';\n\nlet redis: Redis;\n\nexport function getUpstashRedis(): Redis {\n if (!redis) {\n redis = new Redis({\n url: process.env.UPSTASH_REDIS_REST_URL!,\n token: process.env.UPSTASH_REDIS_REST_TOKEN!,\n });\n }\n return redis;\n}\n\nexport async function get<T = any>(key: string): Promise<T | null> {\n return getUpstashRedis().get<T>(key);\n}\n\nexport async function set(key: string, value: any, ttlSeconds?: number) {\n const client = getUpstashRedis();\n if (ttlSeconds) {\n return client.set(key, value, { ex: ttlSeconds });\n }\n return client.set(key, value);\n}\n\nexport async function del(key: string) {\n return getUpstashRedis().del(key);\n}\n\nexport async function incr(key: string) {\n return getUpstashRedis().incr(key);\n}\n`;\n\n await opts.writeFile(`${apiDir}/src/infra/upstash-redis.ts`, serviceContent);\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 flagsmithInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n await ensureDir(path.join(apiDir, 'src', 'infra', 'feature-flags'));\n\n envEntries.push(\n { key: 'FLAGSMITH_ENVIRONMENT_KEY', value: '', category: 'Flagsmith', comment: 'Obtenha em https://flagsmith.com' },\n );\n\n if (config.backend === 'nestjs') {\n await writeFile(path.join(apiDir, 'src', 'infra', 'feature-flags', 'flagsmith.service.ts'), `import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Flagsmith from 'flagsmith-nodejs';\n\n@Injectable()\nexport class FlagsmithService implements OnModuleInit {\n private client!: Flagsmith;\n\n constructor(private configService: ConfigService) {}\n\n async onModuleInit() {\n this.client = new Flagsmith({\n environmentKey: this.configService.get('FLAGSMITH_ENVIRONMENT_KEY', ''),\n });\n\n await this.client.getEnvironmentFlags();\n console.log('Flagsmith inicializado');\n }\n\n /**\n * Verifica se uma feature flag esta habilitada.\n * @param featureName - Nome da feature flag.\n * @param identity - Identificador do usuario (opcional, para flags por usuario).\n */\n async isEnabled(featureName: string, identity?: string): Promise<boolean> {\n if (identity) {\n const flags = await this.client.getIdentityFlags(identity);\n return flags.isFeatureEnabled(featureName);\n }\n\n const flags = await this.client.getEnvironmentFlags();\n return flags.isFeatureEnabled(featureName);\n }\n\n /**\n * Retorna o valor de uma feature flag.\n * @param featureName - Nome da feature flag.\n * @param identity - Identificador do usuario (opcional).\n */\n async getValue(featureName: string, identity?: string): Promise<string | number | boolean | null> {\n if (identity) {\n const flags = await this.client.getIdentityFlags(identity);\n return flags.getFeatureValue(featureName);\n }\n\n const flags = await this.client.getEnvironmentFlags();\n return flags.getFeatureValue(featureName);\n }\n\n /**\n * Retorna todas as flags para um usuario especifico.\n * @param identity - Identificador do usuario.\n */\n async getIdentityFlags(identity: string) {\n return this.client.getIdentityFlags(identity);\n }\n}\n`);\n } else {\n await writeFile(path.join(apiDir, 'src', 'infra', 'feature-flags', 'flagsmith.ts'), `import Flagsmith from 'flagsmith-nodejs';\n\nconst client = new Flagsmith({\n environmentKey: process.env.FLAGSMITH_ENVIRONMENT_KEY || '',\n});\n\n// Inicializa as flags do ambiente\nclient.getEnvironmentFlags().then(() => {\n console.log('Flagsmith inicializado');\n}).catch((err) => {\n console.error('Erro ao inicializar Flagsmith:', err);\n});\n\n/**\n * Verifica se uma feature flag esta habilitada.\n *\n * Uso:\n * import { isEnabled, getValue } from './infra/feature-flags/flagsmith.js';\n *\n * if (await isEnabled('new_dashboard')) {\n * // Mostrar novo dashboard\n * }\n *\n * @param featureName - Nome da feature flag.\n * @param identity - Identificador do usuario (opcional, para flags por usuario).\n */\nexport async function isEnabled(featureName: string, identity?: string): Promise<boolean> {\n if (identity) {\n const flags = await client.getIdentityFlags(identity);\n return flags.isFeatureEnabled(featureName);\n }\n\n const flags = await client.getEnvironmentFlags();\n return flags.isFeatureEnabled(featureName);\n}\n\n/**\n * Retorna o valor de uma feature flag.\n * @param featureName - Nome da feature flag.\n * @param identity - Identificador do usuario (opcional).\n */\nexport async function getValue(featureName: string, identity?: string): Promise<string | number | boolean | null> {\n if (identity) {\n const flags = await client.getIdentityFlags(identity);\n return flags.getFeatureValue(featureName);\n }\n\n const flags = await client.getEnvironmentFlags();\n return flags.getFeatureValue(featureName);\n}\n\n/**\n * Retorna todas as flags para um usuario especifico.\n * @param identity - Identificador do usuario.\n */\nexport async function getIdentityFlags(identity: string) {\n return client.getIdentityFlags(identity);\n}\n\nexport default { isEnabled, getValue, getIdentityFlags };\n`);\n }\n\n dependencies['flagsmith-nodejs'] = deps['flagsmith-nodejs'];\n};\n","import { InstallerFn } from '../../types/installer.js';\n\nexport const launchDarklyInstaller: InstallerFn = async (opts) => {\n const { config, apiDir, envEntries, dependencies } = opts;\n\n dependencies['launchdarkly-node-server-sdk'] = '^7.0.3';\n\n envEntries.push(\n '# LaunchDarkly',\n 'LAUNCHDARKLY_SDK_KEY=your-sdk-key',\n ''\n );\n\n const isNest = config.backend === 'nestjs';\n const isExpress = config.backend === 'express';\n\n if (isNest) {\n const serviceContent = `import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';\nimport * as LaunchDarkly from 'launchdarkly-node-server-sdk';\n\n@Injectable()\nexport class LaunchDarklyService implements OnModuleInit, OnModuleDestroy {\n private client: LaunchDarkly.LDClient;\n\n async onModuleInit() {\n this.client = LaunchDarkly.init(process.env.LAUNCHDARKLY_SDK_KEY!);\n await this.client.waitForInitialization();\n }\n\n async onModuleDestroy() {\n await this.client.close();\n }\n\n async getFlag(key: string, user: LaunchDarkly.LDUser, defaultValue: boolean = false): Promise<boolean> {\n return this.client.variation(key, user, defaultValue);\n }\n\n async getAllFlags(user: LaunchDarkly.LDUser) {\n return this.client.allFlagsState(user);\n }\n}\n`;\n\n const moduleContent = `import { Module, Global } from '@nestjs/common';\nimport { LaunchDarklyService } from './launchdarkly.service';\n\n@Global()\n@Module({\n providers: [LaunchDarklyService],\n exports: [LaunchDarklyService],\n})\nexport class LaunchDarklyModule {}\n`;\n\n await opts.writeFile(`${apiDir}/src/feature-flags/launchdarkly.service.ts`, serviceContent);\n await opts.writeFile(`${apiDir}/src/feature-flags/launchdarkly.module.ts`, moduleContent);\n } else {\n const serviceContent = `import * as LaunchDarkly from 'launchdarkly-node-server-sdk';\n\nlet client: LaunchDarkly.LDClient;\n\nexport async function initLaunchDarkly() {\n client = LaunchDarkly.init(process.env.LAUNCHDARKLY_SDK_KEY!);\n await client.waitForInitialization();\n console.log('LaunchDarkly initialized');\n return client;\n}\n\nexport async function getFlag(key: string, user: LaunchDarkly.LDUser, defaultValue: boolean = false): Promise<boolean> {\n return client.variation(key, user, defaultValue);\n}\n\nexport async function getAllFlags(user: LaunchDarkly.LDUser) {\n return client.allFlagsState(user);\n}\n\nexport async function closeLaunchDarkly() {\n await client.close();\n}\n`;\n\n await opts.writeFile(`${apiDir}/src/feature-flags/launchdarkly.ts`, serviceContent);\n\n if (isExpress) {\n const middlewareContent = `import { Request, Response, NextFunction } from 'express';\nimport { getFlag } from './launchdarkly';\n\nexport function featureFlag(flagKey: string) {\n return async (req: Request, res: Response, next: NextFunction) => {\n const user = { key: (req as any).user?.id || 'anonymous' };\n const enabled = await getFlag(flagKey, user);\n if (!enabled) {\n return res.status(404).json({ message: 'Feature not available' });\n }\n next();\n };\n}\n`;\n await opts.writeFile(`${apiDir}/src/feature-flags/feature-flag.middleware.ts`, middlewareContent);\n }\n }\n};\n","import type { InstallerFn } from '../../types/installers.js';\nimport { dependencyVersionMap as deps } from '../dependencyVersionMap.js';\n\nexport const compressionInstaller: InstallerFn = async (opts) => {\n const { config, dependencies, devDependencies } = opts;\n\n if (config.backend === 'fastify') {\n dependencies['@fastify/compress'] = deps['@fastify/compress'];\n } else {\n // NestJS e Express usam o pacote compression\n dependencies['compression'] = deps.compression;\n devDependencies['@types/compression'] = deps['@types/compression'];\n }\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// 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\n// v3.0 installers\nimport { githubOauthInstaller } from './auth/githubOauth.js';\nimport { appleSignInInstaller } from './auth/appleSignIn.js';\nimport { discordOauthInstaller } from './auth/discordOauth.js';\nimport { clerkInstaller } from './auth/clerk.js';\nimport { nextAuthInstaller } from './auth/nextAuth.js';\nimport { totpInstaller } from './security/totp.js';\nimport { sentryInstaller } from './monitoring/sentry.js';\nimport { resendInstaller } from './infra/resend.js';\nimport { awsS3Installer } from './infra/awsS3.js';\nimport { cloudflareR2Installer } from './infra/cloudflareR2.js';\nimport { trpcInstaller } from './api/trpc.js';\nimport { twilioSmsInstaller } from './integrations/twilioSms.js';\nimport { telegramBotInstaller } from './integrations/telegramBot.js';\nimport { openaiInstaller } from './integrations/openai.js';\nimport { vercelAiInstaller } from './integrations/vercelAi.js';\nimport { paypalInstaller } from './integrations/paypal.js';\nimport { vitestInstaller } from './testing/vitest.js';\nimport { googleAnalyticsInstaller } from './analytics/googleAnalytics.js';\nimport { meilisearchInstaller } from './search/meilisearch.js';\nimport { nodeCronInstaller } from './scheduling/nodeCron.js';\nimport { pdfkitInstaller } from './pdf/pdfkit.js';\nimport { healthChecksInstaller } from './misc/healthChecks.js';\n\n// v3.1 installers — Auth\nimport { facebookOauthInstaller } from './auth/facebookOauth.js';\nimport { microsoftOauthInstaller } from './auth/microsoftOauth.js';\nimport { linkedinOauthInstaller } from './auth/linkedinOauth.js';\nimport { twitterOauthInstaller } from './auth/twitterOauth.js';\nimport { spotifyOauthInstaller } from './auth/spotifyOauth.js';\nimport { auth0Installer } from './auth/auth0.js';\nimport { supabaseAuthInstaller } from './auth/supabaseAuth.js';\n\n// v3.1 installers — Email\nimport { sendgridInstaller } from './infra/sendgrid.js';\nimport { amazonSesInstaller } from './infra/amazonSes.js';\n\n// v3.1 installers — Analytics\nimport { posthogInstaller } from './analytics/posthog.js';\nimport { plausibleInstaller } from './analytics/plausible.js';\nimport { mixpanelInstaller } from './analytics/mixpanel.js';\n\n// v3.1 installers — Search\nimport { algoliaInstaller } from './search/algolia.js';\nimport { elasticsearchInstaller } from './search/elasticsearch.js';\nimport { typesenseInstaller } from './search/typesense.js';\n\n// v3.1 installers — API\nimport { graphqlInstaller } from './api/graphql.js';\n\n// v3.1 installers — Security\nimport { recaptchaInstaller } from './security/recaptcha.js';\n\n// v3.1 installers — Testing\nimport { playwrightInstaller } from './testing/playwright.js';\n\n// v3.1 installers — Scheduling\nimport { inngestInstaller } from './scheduling/inngest.js';\n\n// v3.1 installers — PDF\nimport { puppeteerInstaller } from './pdf/puppeteer.js';\n\n// v3.1 installers — CMS\nimport { strapiInstaller } from './cms/strapi.js';\nimport { sanityInstaller } from './cms/sanity.js';\n\n// v3.1 installers — Integrations\nimport { paddleInstaller } from './integrations/paddle.js';\nimport { lemonSqueezyInstaller } from './integrations/lemonSqueezy.js';\nimport { pagSeguroInstaller } from './integrations/pagSeguro.js';\nimport { asaasInstaller } from './integrations/asaas.js';\nimport { anthropicInstaller } from './integrations/anthropic.js';\nimport { googleGeminiInstaller } from './integrations/googleGemini.js';\nimport { langchainInstaller } from './integrations/langchain.js';\nimport { slackWebhookInstaller } from './integrations/slackWebhook.js';\nimport { discordWebhookInstaller } from './integrations/discordWebhook.js';\nimport { firebaseFcmInstaller } from './integrations/firebaseFcm.js';\nimport { oneSignalInstaller } from './integrations/oneSignal.js';\nimport { mapboxInstaller } from './integrations/mapbox.js';\nimport { hotjarInstaller } from './integrations/hotjar.js';\nimport { cloudinaryInstaller } from './integrations/cloudinary.js';\nimport { uploadThingInstaller } from './integrations/uploadThing.js';\nimport { googleMapsInstaller } from './integrations/googleMaps.js';\n\n// v3.1 installers — BaaS\nimport { supabaseInstaller } from './baas/supabase.js';\nimport { firebaseInstaller } from './baas/firebase.js';\nimport { neonDbInstaller } from './baas/neonDb.js';\nimport { upstashRedisInstaller } from './baas/upstashRedis.js';\n\n// v3.1 installers — Feature Flags\nimport { flagsmithInstaller } from './featureFlags/flagsmith.js';\nimport { launchDarklyInstaller } from './featureFlags/launchDarkly.js';\n\n// v3.1 installers — Misc\nimport { compressionInstaller } from './misc/compression.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 'Resend': {\n inUse: config.resend,\n installer: resendInstaller,\n },\n 'SendGrid': {\n inUse: config.sendgrid,\n installer: sendgridInstaller,\n },\n 'Amazon SES': {\n inUse: config.amazonSes,\n installer: amazonSesInstaller,\n },\n 'MinIO': {\n inUse: config.minio,\n installer: minioInstaller,\n },\n 'AWS S3': {\n inUse: config.awsS3,\n installer: awsS3Installer,\n },\n 'Cloudflare R2': {\n inUse: config.cloudflareR2,\n installer: cloudflareR2Installer,\n },\n 'PM2': {\n inUse: config.pm2,\n installer: pm2Installer,\n },\n 'WebSockets': {\n inUse: config.websockets,\n installer: websocketsInstaller,\n },\n\n // Auth — OAuth Providers (11)\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 'GitHub OAuth': {\n inUse: config.auth.githubOAuth,\n installer: githubOauthInstaller,\n },\n 'Apple Sign-In': {\n inUse: config.auth.appleSignIn,\n installer: appleSignInInstaller,\n },\n 'Discord OAuth': {\n inUse: config.auth.discordOAuth,\n installer: discordOauthInstaller,\n },\n 'Facebook OAuth': {\n inUse: config.auth.facebookOAuth,\n installer: facebookOauthInstaller,\n },\n 'Microsoft OAuth': {\n inUse: config.auth.microsoftOAuth,\n installer: microsoftOauthInstaller,\n },\n 'LinkedIn OAuth': {\n inUse: config.auth.linkedinOAuth,\n installer: linkedinOauthInstaller,\n },\n 'Twitter OAuth': {\n inUse: config.auth.twitterOAuth,\n installer: twitterOauthInstaller,\n },\n 'Spotify OAuth': {\n inUse: config.auth.spotifyOAuth,\n installer: spotifyOauthInstaller,\n },\n\n // Auth Services (5)\n 'Clerk': {\n inUse: config.clerk,\n installer: clerkInstaller,\n },\n 'NextAuth': {\n inUse: config.nextAuth,\n installer: nextAuthInstaller,\n },\n 'Auth0': {\n inUse: config.auth0,\n installer: auth0Installer,\n },\n 'Supabase Auth': {\n inUse: config.supabaseAuth,\n installer: supabaseAuthInstaller,\n },\n\n // Security (2)\n '2FA/TOTP': {\n inUse: config.totp,\n installer: totpInstaller,\n },\n 'reCAPTCHA': {\n inUse: config.recaptcha,\n installer: recaptchaInstaller,\n },\n\n // SaaS Features (3)\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 (8)\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 'tRPC': {\n inUse: config.trpc,\n installer: trpcInstaller,\n },\n 'GraphQL': {\n inUse: config.graphql,\n installer: graphqlInstaller,\n },\n 'Health Checks': {\n inUse: config.healthChecks,\n installer: healthChecksInstaller,\n },\n 'Compression': {\n inUse: config.compression,\n installer: compressionInstaller,\n },\n\n // Monitoring & Analytics (5)\n 'Sentry': {\n inUse: config.sentry,\n installer: sentryInstaller,\n },\n 'Google Analytics': {\n inUse: config.googleAnalytics,\n installer: googleAnalyticsInstaller,\n },\n 'PostHog': {\n inUse: config.posthog,\n installer: posthogInstaller,\n },\n 'Plausible': {\n inUse: config.plausible,\n installer: plausibleInstaller,\n },\n 'Mixpanel': {\n inUse: config.mixpanel,\n installer: mixpanelInstaller,\n },\n\n // Testing (2)\n 'Vitest': {\n inUse: config.vitest,\n installer: vitestInstaller,\n },\n 'Playwright': {\n inUse: config.playwright,\n installer: playwrightInstaller,\n },\n\n // Search (4)\n 'Meilisearch': {\n inUse: config.meilisearch,\n installer: meilisearchInstaller,\n },\n 'Algolia': {\n inUse: config.algolia,\n installer: algoliaInstaller,\n },\n 'Elasticsearch': {\n inUse: config.elasticsearch,\n installer: elasticsearchInstaller,\n },\n 'Typesense': {\n inUse: config.typesense,\n installer: typesenseInstaller,\n },\n\n // Scheduling (2)\n 'Cron Jobs': {\n inUse: config.nodeCron,\n installer: nodeCronInstaller,\n },\n 'Inngest': {\n inUse: config.inngest,\n installer: inngestInstaller,\n },\n\n // PDF (2)\n 'PDFKit': {\n inUse: config.pdfkit,\n installer: pdfkitInstaller,\n },\n 'Puppeteer PDF': {\n inUse: config.puppeteer,\n installer: puppeteerInstaller,\n },\n\n // CMS (2)\n 'Strapi': {\n inUse: config.strapi,\n installer: strapiInstaller,\n },\n 'Sanity': {\n inUse: config.sanity,\n installer: sanityInstaller,\n },\n\n // BaaS (4)\n 'Supabase': {\n inUse: config.supabase,\n installer: supabaseInstaller,\n },\n 'Firebase': {\n inUse: config.firebase,\n installer: firebaseInstaller,\n },\n 'Neon DB': {\n inUse: config.neonDb,\n installer: neonDbInstaller,\n },\n 'Upstash Redis': {\n inUse: config.upstashRedis,\n installer: upstashRedisInstaller,\n },\n\n // Feature Flags (2)\n 'Flagsmith': {\n inUse: config.flagsmith,\n installer: flagsmithInstaller,\n },\n 'LaunchDarkly': {\n inUse: config.launchDarkly,\n installer: launchDarklyInstaller,\n },\n\n // i18n\n 'i18n': {\n inUse: config.i18n,\n installer: i18nInstaller,\n },\n\n // Queues (2)\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 — Payments (8)\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 'PayPal': {\n inUse: config.integrations.paypal,\n installer: paypalInstaller,\n },\n 'Paddle': {\n inUse: config.integrations.paddle,\n installer: paddleInstaller,\n },\n 'Lemon Squeezy': {\n inUse: config.integrations.lemonSqueezy,\n installer: lemonSqueezyInstaller,\n },\n 'PagSeguro': {\n inUse: config.integrations.pagSeguro,\n installer: pagSeguroInstaller,\n },\n 'Asaas': {\n inUse: config.integrations.asaas,\n installer: asaasInstaller,\n },\n\n // Integrations — AI (5)\n 'OpenAI': {\n inUse: config.integrations.openai,\n installer: openaiInstaller,\n },\n 'Vercel AI SDK': {\n inUse: config.integrations.vercelAi,\n installer: vercelAiInstaller,\n },\n 'Anthropic': {\n inUse: config.integrations.anthropic,\n installer: anthropicInstaller,\n },\n 'Google Gemini': {\n inUse: config.integrations.googleGemini,\n installer: googleGeminiInstaller,\n },\n 'LangChain': {\n inUse: config.integrations.langchain,\n installer: langchainInstaller,\n },\n\n // Integrations — Communication (7)\n 'Twilio SMS': {\n inUse: config.integrations.twilioSms,\n installer: twilioSmsInstaller,\n },\n 'Telegram Bot': {\n inUse: config.integrations.telegramBot,\n installer: telegramBotInstaller,\n },\n 'Slack Webhook': {\n inUse: config.integrations.slackWebhook,\n installer: slackWebhookInstaller,\n },\n 'Discord Webhook': {\n inUse: config.integrations.discordWebhook,\n installer: discordWebhookInstaller,\n },\n 'Firebase FCM': {\n inUse: config.integrations.firebaseFcm,\n installer: firebaseFcmInstaller,\n },\n 'OneSignal': {\n inUse: config.integrations.oneSignal,\n installer: oneSignalInstaller,\n },\n\n // Integrations — Other\n 'Mapbox': {\n inUse: config.integrations.mapbox,\n installer: mapboxInstaller,\n },\n 'Hotjar': {\n inUse: config.integrations.hotjar,\n installer: hotjarInstaller,\n },\n 'Cloudinary': {\n inUse: config.integrations.cloudinary,\n installer: cloudinaryInstaller,\n },\n 'UploadThing': {\n inUse: config.integrations.uploadThing,\n installer: uploadThingInstaller,\n },\n 'Google Maps': {\n inUse: config.integrations.googleMaps,\n installer: googleMapsInstaller,\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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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0FrB,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;AAA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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","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","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","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","execa","path","chalk","confirm","chalk","fs"]}