ar-saas 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +338 -314
  3. package/dist/cli.js +19 -0
  4. package/dist/generator.js +166 -55
  5. package/package.json +52 -50
  6. package/templates/backend/.env.example +67 -67
  7. package/templates/backend/.prettierrc +4 -4
  8. package/templates/backend/README.md +249 -168
  9. package/templates/backend/eslint.config.mjs +35 -35
  10. package/templates/backend/nest-cli.json +8 -8
  11. package/templates/backend/package-lock.json +10979 -10979
  12. package/templates/backend/package.json +88 -88
  13. package/templates/backend/src/app.controller.spec.ts +24 -24
  14. package/templates/backend/src/app.controller.ts +15 -15
  15. package/templates/backend/src/app.module.ts +40 -40
  16. package/templates/backend/src/app.service.ts +11 -11
  17. package/templates/backend/src/common/base/base.repository.ts +221 -221
  18. package/templates/backend/src/common/base/base.schema.ts +24 -24
  19. package/templates/backend/src/common/decorators/cookie.decorator.ts +9 -9
  20. package/templates/backend/src/common/decorators/current-user.decorator.ts +20 -20
  21. package/templates/backend/src/common/decorators/workspace-id.decorator.ts +14 -14
  22. package/templates/backend/src/common/filters/global-exception.filter.ts +61 -61
  23. package/templates/backend/src/common/guards/jwt-auth.guard.ts +5 -5
  24. package/templates/backend/src/common/interceptors/workspace-tenant.interceptor.ts +45 -45
  25. package/templates/backend/src/main.ts +51 -51
  26. package/templates/backend/src/modules/auth/auth.controller.ts +158 -158
  27. package/templates/backend/src/modules/auth/auth.module.ts +20 -20
  28. package/templates/backend/src/modules/auth/auth.service.ts +257 -257
  29. package/templates/backend/src/modules/auth/dto/forgot-password.dto.ts +9 -9
  30. package/templates/backend/src/modules/auth/dto/login.dto.ts +14 -14
  31. package/templates/backend/src/modules/auth/dto/refresh-token.dto.ts +12 -12
  32. package/templates/backend/src/modules/auth/dto/register.dto.ts +26 -26
  33. package/templates/backend/src/modules/auth/dto/reset-password.dto.ts +16 -16
  34. package/templates/backend/src/modules/auth/dto/verify-email.dto.ts +9 -9
  35. package/templates/backend/src/modules/auth/strategies/jwt.strategy.ts +43 -43
  36. package/templates/backend/src/modules/mail/mail.module.ts +9 -9
  37. package/templates/backend/src/modules/mail/mail.service.ts +141 -141
  38. package/templates/backend/src/modules/users/schemas/user.schema.ts +54 -54
  39. package/templates/backend/src/modules/users/users.module.ts +14 -14
  40. package/templates/backend/src/modules/users/users.repository.ts +51 -51
  41. package/templates/backend/src/modules/users/users.service.ts +104 -104
  42. package/templates/backend/src/modules/workspaces/schemas/workspace.schema.ts +26 -26
  43. package/templates/backend/src/modules/workspaces/workspaces.module.ts +16 -16
  44. package/templates/backend/src/modules/workspaces/workspaces.repository.ts +34 -34
  45. package/templates/backend/src/modules/workspaces/workspaces.service.ts +42 -42
  46. package/templates/backend/test/app.e2e-spec.ts +25 -25
  47. package/templates/backend/test/jest-e2e.json +9 -9
  48. package/templates/backend/tsconfig.build.json +4 -4
  49. package/templates/backend/tsconfig.json +26 -26
  50. package/templates/frontend/.env.local.example +1 -1
  51. package/templates/frontend/README.md +152 -0
  52. package/templates/frontend/components.json +20 -20
  53. package/templates/frontend/eslint.config.mjs +14 -14
  54. package/templates/frontend/next.config.ts +5 -5
  55. package/templates/frontend/package-lock.json +6722 -6722
  56. package/templates/frontend/package.json +48 -48
  57. package/templates/frontend/pnpm-lock.yaml +5012 -5012
  58. package/templates/frontend/pnpm-workspace.yaml +3 -3
  59. package/templates/frontend/postcss.config.mjs +7 -7
  60. package/templates/frontend/src/app/(auth)/forgot-password/page.tsx +84 -84
  61. package/templates/frontend/src/app/(auth)/layout.tsx +28 -28
  62. package/templates/frontend/src/app/(auth)/login/page.tsx +111 -111
  63. package/templates/frontend/src/app/(auth)/register/page.tsx +161 -161
  64. package/templates/frontend/src/app/(auth)/reset-password/page.tsx +120 -120
  65. package/templates/frontend/src/app/(auth)/verify-email/page.tsx +78 -78
  66. package/templates/frontend/src/app/(dashboard)/billing/page.tsx +111 -111
  67. package/templates/frontend/src/app/(dashboard)/dashboard/page.tsx +105 -105
  68. package/templates/frontend/src/app/(dashboard)/layout.tsx +38 -38
  69. package/templates/frontend/src/app/(dashboard)/profile/page.tsx +226 -226
  70. package/templates/frontend/src/app/(dashboard)/settings/page.tsx +156 -156
  71. package/templates/frontend/src/app/(dashboard)/team/page.tsx +178 -178
  72. package/templates/frontend/src/app/(legal)/privacy/page.tsx +127 -127
  73. package/templates/frontend/src/app/(legal)/terms/page.tsx +118 -118
  74. package/templates/frontend/src/app/globals.css +81 -81
  75. package/templates/frontend/src/app/layout.tsx +26 -26
  76. package/templates/frontend/src/app/page.tsx +5 -45
  77. package/templates/frontend/src/app/setup/page.tsx +371 -275
  78. package/templates/frontend/src/components/dashboard/header.tsx +89 -89
  79. package/templates/frontend/src/components/dashboard/sidebar.tsx +71 -71
  80. package/templates/frontend/src/components/dashboard/stat-card.tsx +34 -34
  81. package/templates/frontend/src/components/landing/faq.tsx +39 -39
  82. package/templates/frontend/src/components/landing/features.tsx +54 -54
  83. package/templates/frontend/src/components/landing/footer.tsx +76 -76
  84. package/templates/frontend/src/components/landing/hero.tsx +72 -72
  85. package/templates/frontend/src/components/landing/navbar.tsx +78 -78
  86. package/templates/frontend/src/components/landing/pricing.tsx +90 -90
  87. package/templates/frontend/src/components/ui/accordion.tsx +52 -52
  88. package/templates/frontend/src/components/ui/avatar.tsx +46 -46
  89. package/templates/frontend/src/components/ui/badge.tsx +30 -30
  90. package/templates/frontend/src/components/ui/button.tsx +52 -52
  91. package/templates/frontend/src/components/ui/card.tsx +50 -50
  92. package/templates/frontend/src/components/ui/checkbox.tsx +27 -27
  93. package/templates/frontend/src/components/ui/dialog.tsx +100 -100
  94. package/templates/frontend/src/components/ui/dropdown-menu.tsx +173 -173
  95. package/templates/frontend/src/components/ui/form.tsx +158 -158
  96. package/templates/frontend/src/components/ui/input.tsx +21 -21
  97. package/templates/frontend/src/components/ui/label.tsx +22 -22
  98. package/templates/frontend/src/components/ui/separator.tsx +25 -25
  99. package/templates/frontend/src/components/ui/skeleton.tsx +7 -7
  100. package/templates/frontend/src/components/ui/switch.tsx +28 -28
  101. package/templates/frontend/src/components/ui/tabs.tsx +54 -54
  102. package/templates/frontend/src/components/ui/textarea.tsx +20 -20
  103. package/templates/frontend/src/components/ui/toast.tsx +109 -109
  104. package/templates/frontend/src/components/ui/toaster.tsx +30 -30
  105. package/templates/frontend/src/config/site.ts +197 -197
  106. package/templates/frontend/src/hooks/use-toast.ts +116 -116
  107. package/templates/frontend/src/lib/api/auth.ts +39 -39
  108. package/templates/frontend/src/lib/api/client.ts +66 -66
  109. package/templates/frontend/src/lib/hooks/use-auth.ts +1 -1
  110. package/templates/frontend/src/lib/utils.ts +6 -6
  111. package/templates/frontend/src/providers/auth-provider.tsx +60 -60
  112. package/templates/frontend/src/types/api.ts +12 -12
  113. package/templates/frontend/src/types/auth.ts +27 -27
  114. package/templates/frontend/tsconfig.json +23 -23
package/dist/cli.js CHANGED
@@ -85,6 +85,25 @@ async function runCli(defaultName) {
85
85
  { name: 'Después', value: 'later' },
86
86
  ],
87
87
  },
88
+ {
89
+ type: 'list',
90
+ name: 'mongoMode',
91
+ message: '¿Dónde va a estar tu base de datos MongoDB?',
92
+ when: (answers) => answers.stack === 'backend' || answers.stack === 'backend-frontend',
93
+ choices: [
94
+ { name: 'Local con Docker (recomendado para desarrollo)', value: 'docker' },
95
+ { name: 'URL remota (MongoDB Atlas u otro)', value: 'remote' },
96
+ ],
97
+ },
98
+ {
99
+ type: 'input',
100
+ name: 'mongoUri',
101
+ message: 'Ingresá la URI de MongoDB:',
102
+ when: (answers) => answers.mongoMode === 'remote',
103
+ validate: (input) => input.startsWith('mongodb://') || input.startsWith('mongodb+srv://')
104
+ ? true
105
+ : 'La URI debe comenzar con mongodb:// o mongodb+srv://',
106
+ },
88
107
  ]);
89
108
  return answers;
90
109
  }
package/dist/generator.js CHANGED
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.generate = generate;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
+ const child_process_1 = require("child_process");
9
10
  const fs_extra_1 = __importDefault(require("fs-extra"));
10
11
  const chalk_1 = __importDefault(require("chalk"));
11
12
  const ora_1 = __importDefault(require("ora"));
@@ -62,13 +63,30 @@ async function generate(config) {
62
63
  }
63
64
  spinner.text = 'Generando configuración de deploy...';
64
65
  generateDeployConfig(projectDir, config);
66
+ spinner.text = 'Generando entorno de desarrollo...';
67
+ generateDevConfig(projectDir, config);
65
68
  spinner.text = 'Configurando variables de entorno...';
66
69
  setupEnvFiles(projectDir, config);
70
+ let dockerStarted = false;
71
+ if (hasBackend) {
72
+ if (config.mongoMode === 'remote' && config.mongoUri) {
73
+ patchMongoUri(projectDir, config.mongoUri);
74
+ }
75
+ else {
76
+ const dockerAvailable = await detectDocker();
77
+ if (dockerAvailable) {
78
+ dockerStarted = await startDockerMongo(projectDir, config, spinner);
79
+ }
80
+ else {
81
+ printNoDockerWarning();
82
+ }
83
+ }
84
+ }
67
85
  spinner.succeed(chalk_1.default.green(`Proyecto ${chalk_1.default.bold(config.projectName)} creado`));
68
86
  console.log();
69
87
  console.log(chalk_1.default.cyan(` Sitio: ${chalk_1.default.bold(config.siteTitle)}`));
70
88
  console.log(chalk_1.default.gray(` "${config.siteTagline}"`));
71
- printNextSteps(config);
89
+ printNextSteps(config, dockerStarted);
72
90
  }
73
91
  function processDir(dir, config) {
74
92
  for (const file of collectTextFiles(dir)) {
@@ -124,76 +142,101 @@ function generateDeployConfig(projectDir, config) {
124
142
  fs_1.default.writeFileSync(path_1.default.join(projectDir, 'fly.toml'), buildFlyConfig(config), 'utf-8');
125
143
  }
126
144
  }
145
+ function generateDevConfig(projectDir, config) {
146
+ const hasBackend = config.stack === 'backend' || config.stack === 'backend-frontend';
147
+ if (!hasBackend)
148
+ return;
149
+ fs_1.default.writeFileSync(path_1.default.join(projectDir, 'docker-compose.dev.yml'), buildDockerComposeDev(config), 'utf-8');
150
+ }
151
+ function buildDockerComposeDev(config) {
152
+ return `# Base de datos local para desarrollo
153
+ # Levantá con: docker compose -f docker-compose.dev.yml up -d
154
+ # Para usar una BD remota (ej. MongoDB Atlas), cambiá MONGODB_URI en backend/.env
155
+
156
+ services:
157
+ mongodb:
158
+ image: mongo:7
159
+ container_name: ${config.projectName}-mongo-dev
160
+ ports:
161
+ - "27017:27017"
162
+ volumes:
163
+ - ${config.projectName}_mongo_dev:/data/db
164
+ restart: unless-stopped
165
+
166
+ volumes:
167
+ ${config.projectName}_mongo_dev:
168
+ `;
169
+ }
127
170
  function buildDockerCompose(config) {
128
171
  const hasBackend = config.stack === 'backend' || config.stack === 'backend-frontend';
129
172
  const hasFrontend = config.stack === 'frontend' || config.stack === 'backend-frontend';
130
173
  const services = [];
131
174
  if (hasBackend) {
132
- services.push(` backend:
133
- build: ./backend
134
- ports:
135
- - "3000:3000"
136
- env_file:
137
- - ./backend/.env
138
- depends_on:
139
- - mongodb
140
- restart: unless-stopped
141
-
142
- mongodb:
143
- image: mongo:7
144
- ports:
145
- - "27017:27017"
146
- volumes:
147
- - mongodb_data:/data/db
175
+ services.push(` backend:
176
+ build: ./backend
177
+ ports:
178
+ - "3000:3000"
179
+ env_file:
180
+ - ./backend/.env
181
+ depends_on:
182
+ - mongodb
183
+ restart: unless-stopped
184
+
185
+ mongodb:
186
+ image: mongo:7
187
+ ports:
188
+ - "27017:27017"
189
+ volumes:
190
+ - mongodb_data:/data/db
148
191
  restart: unless-stopped`);
149
192
  }
150
193
  if (hasFrontend) {
151
- services.push(` frontend:
152
- build: ./frontend
153
- ports:
154
- - "3001:3000"
155
- env_file:
156
- - ./frontend/.env.local
157
- environment:
158
- - NEXT_PUBLIC_API_URL=http://backend:3000
194
+ services.push(` frontend:
195
+ build: ./frontend
196
+ ports:
197
+ - "3001:3000"
198
+ env_file:
199
+ - ./frontend/.env.local
200
+ environment:
201
+ - NEXT_PUBLIC_API_URL=http://backend:3000
159
202
  ${hasBackend ? 'depends_on:\n - backend\n ' : ''}restart: unless-stopped`);
160
203
  }
161
204
  const volumes = hasBackend ? '\nvolumes:\n mongodb_data:' : '';
162
- return `version: '3.8'
163
-
164
- services:
165
- ${services.join('\n\n')}
166
- ${volumes}
205
+ return `version: '3.8'
206
+
207
+ services:
208
+ ${services.join('\n\n')}
209
+ ${volumes}
167
210
  `;
168
211
  }
169
212
  function buildRailwayConfig() {
170
- return `[build]
171
- builder = "nixpacks"
172
-
173
- [deploy]
174
- startCommand = "npm run start:prod"
175
- healthcheckPath = "/api/health"
176
- healthcheckTimeout = 30
177
- restartPolicyType = "on_failure"
213
+ return `[build]
214
+ builder = "nixpacks"
215
+
216
+ [deploy]
217
+ startCommand = "npm run start:prod"
218
+ healthcheckPath = "/api/health"
219
+ healthcheckTimeout = 30
220
+ restartPolicyType = "on_failure"
178
221
  `;
179
222
  }
180
223
  function buildFlyConfig(config) {
181
- return `app = "${config.projectName}"
182
- primary_region = "gru"
183
-
184
- [build]
185
-
186
- [http_service]
187
- internal_port = 3000
188
- force_https = true
189
- auto_stop_machines = true
190
- auto_start_machines = true
191
- min_machines_running = 0
192
-
193
- [[vm]]
194
- memory = "256mb"
195
- cpu_kind = "shared"
196
- cpus = 1
224
+ return `app = "${config.projectName}"
225
+ primary_region = "gru"
226
+
227
+ [build]
228
+
229
+ [http_service]
230
+ internal_port = 3000
231
+ force_https = true
232
+ auto_stop_machines = true
233
+ auto_start_machines = true
234
+ min_machines_running = 0
235
+
236
+ [[vm]]
237
+ memory = "256mb"
238
+ cpu_kind = "shared"
239
+ cpus = 1
197
240
  `;
198
241
  }
199
242
  function setupEnvFiles(projectDir, config) {
@@ -205,6 +248,14 @@ function setupEnvFiles(projectDir, config) {
205
248
  if (fs_1.default.existsSync(example) && !fs_1.default.existsSync(dest)) {
206
249
  fs_extra_1.default.copySync(example, dest);
207
250
  }
251
+ // Set default local URI; will be overwritten by patchMongoUri if remote mode
252
+ if (fs_1.default.existsSync(dest)) {
253
+ let envContent = fs_1.default.readFileSync(dest, 'utf-8');
254
+ if (!envContent.includes('MONGODB_URI')) {
255
+ envContent += `\n# MongoDB local (docker compose -f docker-compose.dev.yml up -d)\n# Para usar Atlas u otra BD remota, reemplazá esta URI\nMONGODB_URI=mongodb://localhost:27017/${config.projectName}\n`;
256
+ fs_1.default.writeFileSync(dest, envContent, 'utf-8');
257
+ }
258
+ }
208
259
  }
209
260
  if (hasFrontend) {
210
261
  const example = path_1.default.join(projectDir, 'frontend', '.env.local.example');
@@ -214,13 +265,72 @@ function setupEnvFiles(projectDir, config) {
214
265
  }
215
266
  }
216
267
  }
217
- function printNextSteps(config) {
268
+ function patchMongoUri(projectDir, uri) {
269
+ const envPath = path_1.default.join(projectDir, 'backend', '.env');
270
+ if (!fs_1.default.existsSync(envPath))
271
+ return;
272
+ let content = fs_1.default.readFileSync(envPath, 'utf-8');
273
+ content = content.replace(/^MONGODB_URI=.*$/m, `MONGODB_URI=${uri}`);
274
+ if (!content.includes('MONGODB_URI')) {
275
+ content += `\nMONGODB_URI=${uri}\n`;
276
+ }
277
+ fs_1.default.writeFileSync(envPath, content, 'utf-8');
278
+ }
279
+ async function detectDocker() {
280
+ return new Promise((resolve) => {
281
+ (0, child_process_1.exec)('docker --version', (err) => resolve(!err));
282
+ });
283
+ }
284
+ async function startDockerMongo(projectDir, config, spinner) {
285
+ spinner.text = 'Levantando MongoDB local con Docker...';
286
+ return new Promise((resolve) => {
287
+ (0, child_process_1.exec)('docker compose -f docker-compose.dev.yml up -d', { cwd: projectDir }, (err, _stdout, stderr) => {
288
+ if (err) {
289
+ spinner.warn(chalk_1.default.yellow('No se pudo levantar MongoDB automáticamente'));
290
+ console.log(chalk_1.default.gray(` Podés levantarlo manualmente: cd ${config.projectName} && docker compose -f docker-compose.dev.yml up -d`));
291
+ if (stderr)
292
+ console.log(chalk_1.default.gray(` Error: ${stderr.trim()}`));
293
+ resolve(false);
294
+ }
295
+ else {
296
+ resolve(true);
297
+ }
298
+ });
299
+ });
300
+ }
301
+ function printNoDockerWarning() {
302
+ console.log();
303
+ console.log(chalk_1.default.yellow(' ⚠ Docker no está instalado o no está corriendo.'));
304
+ console.log(chalk_1.default.gray(' Opciones para la base de datos:'));
305
+ console.log(chalk_1.default.gray(' 1. Instalá Docker Desktop → https://docs.docker.com/get-docker/'));
306
+ console.log(chalk_1.default.gray(' Luego: docker compose -f docker-compose.dev.yml up -d'));
307
+ console.log(chalk_1.default.gray(' 2. Usá MongoDB Atlas (gratis) → https://www.mongodb.com/atlas'));
308
+ console.log(chalk_1.default.gray(' Y editá MONGODB_URI en backend/.env'));
309
+ }
310
+ function printNextSteps(config, dockerStarted) {
218
311
  const hasBackend = config.stack === 'backend' || config.stack === 'backend-frontend';
219
312
  const hasFrontend = config.stack === 'frontend' || config.stack === 'backend-frontend';
220
313
  console.log();
221
314
  console.log(chalk_1.default.bold('Próximos pasos:'));
222
315
  if (hasBackend) {
223
316
  console.log();
317
+ if (config.mongoMode === 'remote') {
318
+ console.log(chalk_1.default.bold.white(' 1. Base de datos:'));
319
+ console.log(chalk_1.default.green(` ✔ MONGODB_URI configurada en backend/.env`));
320
+ console.log(chalk_1.default.gray(' # Verificá que la URI sea correcta antes de iniciar'));
321
+ }
322
+ else if (dockerStarted) {
323
+ console.log(chalk_1.default.bold.white(' 1. Base de datos:'));
324
+ console.log(chalk_1.default.green(' ✔ MongoDB local levantado con Docker'));
325
+ }
326
+ else {
327
+ console.log(chalk_1.default.bold.white(' 1. Levantá la base de datos:'));
328
+ console.log(chalk_1.default.cyan(` cd ${config.projectName}`));
329
+ console.log(chalk_1.default.cyan(' docker compose -f docker-compose.dev.yml up -d'));
330
+ console.log(chalk_1.default.gray(' # O configurá una URL remota en backend/.env'));
331
+ }
332
+ console.log();
333
+ console.log(chalk_1.default.bold.white(' 2. Iniciá el backend:'));
224
334
  console.log(chalk_1.default.cyan(` cd ${config.projectName}/backend`));
225
335
  console.log(chalk_1.default.gray(' # Completar las variables en .env'));
226
336
  console.log(chalk_1.default.cyan(' npm install'));
@@ -228,6 +338,7 @@ function printNextSteps(config) {
228
338
  }
229
339
  if (hasFrontend) {
230
340
  console.log();
341
+ console.log(chalk_1.default.bold.white(` ${hasBackend ? '3' : '1'}. Iniciá el frontend:`));
231
342
  console.log(chalk_1.default.cyan(` cd ${config.projectName}/frontend`));
232
343
  console.log(chalk_1.default.gray(' # Completar .env.local con la URL del backend'));
233
344
  console.log(chalk_1.default.gray(' # Personalizar contenido en src/config/site.ts'));
package/package.json CHANGED
@@ -1,50 +1,52 @@
1
- {
2
- "name": "ar-saas",
3
- "version": "0.3.1",
4
- "description": "Generador de proyectos SaaS multi-tenant para startups argentinas. Landing page, auth, dashboard y legal listos para producción.",
5
- "main": "dist/index.js",
6
- "bin": {
7
- "ar-saas": "dist/index.js"
8
- },
9
- "files": [
10
- "dist/",
11
- "templates/"
12
- ],
13
- "scripts": {
14
- "build": "tsc",
15
- "dev": "tsx src/index.ts",
16
- "sync-templates": "tsx scripts/sync-templates.ts",
17
- "prepublishOnly": "npm run sync-templates && npm run build"
18
- },
19
- "keywords": [
20
- "saas",
21
- "nestjs",
22
- "nextjs",
23
- "argentina",
24
- "cli",
25
- "generator",
26
- "multi-tenant",
27
- "landing-page",
28
- "dashboard",
29
- "boilerplate",
30
- "starter"
31
- ],
32
- "author": "ignacio.becher@gmail.com",
33
- "license": "MIT",
34
- "engines": {
35
- "node": ">=18.0.0"
36
- },
37
- "dependencies": {
38
- "chalk": "4.1.2",
39
- "fs-extra": "^11.2.0",
40
- "inquirer": "8.2.6",
41
- "ora": "5.4.1"
42
- },
43
- "devDependencies": {
44
- "@types/fs-extra": "^11.0.0",
45
- "@types/inquirer": "^8.2.12",
46
- "@types/node": "^20.0.0",
47
- "tsx": "^4.7.0",
48
- "typescript": "^5.4.0"
49
- }
50
- }
1
+ {
2
+ "name": "ar-saas",
3
+ "version": "0.3.2",
4
+ "description": "Generador de proyectos SaaS multi-tenant para startups argentinas. Landing page, auth, dashboard y legal listos para producción.",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "ar-saas": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist/",
11
+ "templates/"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsx src/index.ts",
16
+ "sync-templates": "tsx scripts/sync-templates.ts",
17
+ "prepublishOnly": "npm run sync-templates && npm run build"
18
+ },
19
+ "keywords": [
20
+ "saas",
21
+ "nestjs",
22
+ "nextjs",
23
+ "argentina",
24
+ "cli",
25
+ "generator",
26
+ "multi-tenant",
27
+ "landing-page",
28
+ "dashboard",
29
+ "boilerplate",
30
+ "starter",
31
+ "mongodb",
32
+ "docker"
33
+ ],
34
+ "author": "ignacio.becher@gmail.com",
35
+ "license": "MIT",
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "dependencies": {
40
+ "chalk": "4.1.2",
41
+ "fs-extra": "^11.2.0",
42
+ "inquirer": "8.2.6",
43
+ "ora": "5.4.1"
44
+ },
45
+ "devDependencies": {
46
+ "@types/fs-extra": "^11.0.0",
47
+ "@types/inquirer": "^8.2.12",
48
+ "@types/node": "^20.0.0",
49
+ "tsx": "^4.7.0",
50
+ "typescript": "^5.4.0"
51
+ }
52
+ }
@@ -1,67 +1,67 @@
1
- # =========================================
2
- # create-saas-ar Backend
3
- # Variables de entorno
4
- # =========================================
5
- # Copiá este archivo a .env y completá los valores
6
- # =========================================
7
-
8
- # ===== Aplicación =====
9
- # Entorno: development | production | test
10
- NODE_ENV=development
11
-
12
- # Puerto donde corre el servidor
13
- PORT=3000
14
-
15
- # Prefijo para todas las rutas de la API
16
- API_PREFIX=api
17
-
18
- # ===== MongoDB =====
19
- # URI de conexión a MongoDB
20
- # Desarrollo local: mongodb://localhost:27017/saas-ar
21
- # Atlas: mongodb+srv://user:pass@cluster.xxx.mongodb.net/saas-ar
22
- # Con replica set (para transacciones): mongodb://localhost:27017/saas-ar?replicaSet=rs0
23
- MONGODB_URI=mongodb://localhost:27017/saas-ar
24
-
25
- # ===== JWT =====
26
- # Secreto para firmar access tokens (usar openssl rand -hex 64 para generar)
27
- JWT_ACCESS_SECRET=cambiar-por-secreto-seguro
28
-
29
- # Duración del access token (formato: 15m, 1h, 7d)
30
- JWT_ACCESS_EXPIRES_IN=15m
31
-
32
- # Secreto para firmar refresh tokens
33
- JWT_REFRESH_SECRET=cambiar-por-secreto-seguro
34
-
35
- # Duración del refresh token (formato: 15m, 1h, 7d)
36
- JWT_REFRESH_EXPIRES_IN=7d
37
-
38
- # ===== Email (Resend) =====
39
- # API Key de Resend (https://resend.com/api-keys)
40
- RESEND_API_KEY=re_cambiar_por_api_key
41
-
42
- # Email remitente (debe estar verificado en Resend)
43
- RESEND_FROM_EMAIL=noreply@tuapp.com
44
-
45
- # Nombre del remitente que ve el destinatario
46
- RESEND_FROM_NAME="Tu App"
47
-
48
- # ===== App URL =====
49
- # URL del frontend (para links en emails de verificación, reset, etc)
50
- APP_URL=http://localhost:5173
51
-
52
- # ===== Swagger =====
53
- # Habilitar documentación Swagger en /api/docs (solo development)
54
- SWAGGER_ENABLED=true
55
-
56
- # ===== CORS =====
57
- # Orígenes permitidos (separados por coma)
58
- CORS_ORIGINS=http://localhost:3001
59
-
60
- # ===== Rate Limiting =====
61
- # Cantidad máxima de requests por ventana de tiempo
62
- THROTTLE_TTL=60
63
- THROTTLE_LIMIT=100
64
-
65
- # ===== Cookies =====
66
- # Secreto para firmar cookies (usar openssl rand -hex 32 para generar)
67
- COOKIE_SECRET=cambiar-por-secreto-seguro
1
+ # =========================================
2
+ # create-saas-ar Backend
3
+ # Variables de entorno
4
+ # =========================================
5
+ # Copiá este archivo a .env y completá los valores
6
+ # =========================================
7
+
8
+ # ===== Aplicación =====
9
+ # Entorno: development | production | test
10
+ NODE_ENV=development
11
+
12
+ # Puerto donde corre el servidor
13
+ PORT=3000
14
+
15
+ # Prefijo para todas las rutas de la API
16
+ API_PREFIX=api
17
+
18
+ # ===== MongoDB =====
19
+ # URI de conexión a MongoDB
20
+ # Desarrollo local: mongodb://localhost:27017/saas-ar
21
+ # Atlas: mongodb+srv://user:pass@cluster.xxx.mongodb.net/saas-ar
22
+ # Con replica set (para transacciones): mongodb://localhost:27017/saas-ar?replicaSet=rs0
23
+ MONGODB_URI=mongodb://localhost:27017/saas-ar
24
+
25
+ # ===== JWT =====
26
+ # Secreto para firmar access tokens (usar openssl rand -hex 64 para generar)
27
+ JWT_ACCESS_SECRET=cambiar-por-secreto-seguro
28
+
29
+ # Duración del access token (formato: 15m, 1h, 7d)
30
+ JWT_ACCESS_EXPIRES_IN=15m
31
+
32
+ # Secreto para firmar refresh tokens
33
+ JWT_REFRESH_SECRET=cambiar-por-secreto-seguro
34
+
35
+ # Duración del refresh token (formato: 15m, 1h, 7d)
36
+ JWT_REFRESH_EXPIRES_IN=7d
37
+
38
+ # ===== Email (Resend) =====
39
+ # API Key de Resend (https://resend.com/api-keys)
40
+ RESEND_API_KEY=re_cambiar_por_api_key
41
+
42
+ # Email remitente (debe estar verificado en Resend)
43
+ RESEND_FROM_EMAIL=noreply@tuapp.com
44
+
45
+ # Nombre del remitente que ve el destinatario
46
+ RESEND_FROM_NAME="Tu App"
47
+
48
+ # ===== App URL =====
49
+ # URL del frontend (para links en emails de verificación, reset, etc)
50
+ APP_URL=http://localhost:5173
51
+
52
+ # ===== Swagger =====
53
+ # Habilitar documentación Swagger en /api/docs (solo development)
54
+ SWAGGER_ENABLED=true
55
+
56
+ # ===== CORS =====
57
+ # Orígenes permitidos (separados por coma)
58
+ CORS_ORIGINS=http://localhost:3001
59
+
60
+ # ===== Rate Limiting =====
61
+ # Cantidad máxima de requests por ventana de tiempo
62
+ THROTTLE_TTL=60
63
+ THROTTLE_LIMIT=100
64
+
65
+ # ===== Cookies =====
66
+ # Secreto para firmar cookies (usar openssl rand -hex 32 para generar)
67
+ COOKIE_SECRET=cambiar-por-secreto-seguro
@@ -1,4 +1,4 @@
1
- {
2
- "singleQuote": true,
3
- "trailingComma": "all"
4
- }
1
+ {
2
+ "singleQuote": true,
3
+ "trailingComma": "all"
4
+ }