ar-saas 0.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/README.md +62 -0
- package/dist/cli.js +67 -0
- package/dist/generator.js +242 -0
- package/dist/index.js +13 -0
- package/dist/license.js +71 -0
- package/package.json +46 -0
- package/templates/backend/.env.example +67 -0
- package/templates/backend/.prettierrc +4 -0
- package/templates/backend/README.md +168 -0
- package/templates/backend/eslint.config.mjs +35 -0
- package/templates/backend/nest-cli.json +8 -0
- package/templates/backend/package-lock.json +10979 -0
- package/templates/backend/package.json +88 -0
- package/templates/backend/src/app.controller.spec.ts +24 -0
- package/templates/backend/src/app.controller.ts +15 -0
- package/templates/backend/src/app.module.ts +40 -0
- package/templates/backend/src/app.service.ts +11 -0
- package/templates/backend/src/common/base/base.repository.ts +221 -0
- package/templates/backend/src/common/base/base.schema.ts +24 -0
- package/templates/backend/src/common/decorators/cookie.decorator.ts +9 -0
- package/templates/backend/src/common/decorators/current-user.decorator.ts +20 -0
- package/templates/backend/src/common/decorators/workspace-id.decorator.ts +14 -0
- package/templates/backend/src/common/filters/global-exception.filter.ts +61 -0
- package/templates/backend/src/common/guards/jwt-auth.guard.ts +5 -0
- package/templates/backend/src/common/interceptors/workspace-tenant.interceptor.ts +45 -0
- package/templates/backend/src/main.ts +51 -0
- package/templates/backend/src/modules/auth/auth.controller.ts +158 -0
- package/templates/backend/src/modules/auth/auth.module.ts +20 -0
- package/templates/backend/src/modules/auth/auth.service.ts +257 -0
- package/templates/backend/src/modules/auth/dto/forgot-password.dto.ts +9 -0
- package/templates/backend/src/modules/auth/dto/login.dto.ts +14 -0
- package/templates/backend/src/modules/auth/dto/refresh-token.dto.ts +12 -0
- package/templates/backend/src/modules/auth/dto/register.dto.ts +26 -0
- package/templates/backend/src/modules/auth/dto/reset-password.dto.ts +16 -0
- package/templates/backend/src/modules/auth/dto/verify-email.dto.ts +9 -0
- package/templates/backend/src/modules/auth/strategies/jwt.strategy.ts +43 -0
- package/templates/backend/src/modules/mail/mail.module.ts +9 -0
- package/templates/backend/src/modules/mail/mail.service.ts +141 -0
- package/templates/backend/src/modules/users/schemas/user.schema.ts +54 -0
- package/templates/backend/src/modules/users/users.module.ts +14 -0
- package/templates/backend/src/modules/users/users.repository.ts +51 -0
- package/templates/backend/src/modules/users/users.service.ts +104 -0
- package/templates/backend/src/modules/workspaces/schemas/workspace.schema.ts +26 -0
- package/templates/backend/src/modules/workspaces/workspaces.module.ts +16 -0
- package/templates/backend/src/modules/workspaces/workspaces.repository.ts +34 -0
- package/templates/backend/src/modules/workspaces/workspaces.service.ts +42 -0
- package/templates/backend/test/app.e2e-spec.ts +25 -0
- package/templates/backend/test/jest-e2e.json +9 -0
- package/templates/backend/tsconfig.build.json +4 -0
- package/templates/backend/tsconfig.json +26 -0
- package/templates/frontend/.env.local.example +1 -0
- package/templates/frontend/components.json +20 -0
- package/templates/frontend/eslint.config.mjs +14 -0
- package/templates/frontend/next.config.ts +5 -0
- package/templates/frontend/package-lock.json +6722 -0
- package/templates/frontend/package.json +40 -0
- package/templates/frontend/postcss.config.mjs +7 -0
- package/templates/frontend/src/app/(auth)/forgot-password/page.tsx +84 -0
- package/templates/frontend/src/app/(auth)/layout.tsx +28 -0
- package/templates/frontend/src/app/(auth)/login/page.tsx +111 -0
- package/templates/frontend/src/app/(auth)/register/page.tsx +119 -0
- package/templates/frontend/src/app/(auth)/reset-password/page.tsx +120 -0
- package/templates/frontend/src/app/(auth)/verify-email/page.tsx +78 -0
- package/templates/frontend/src/app/(dashboard)/dashboard/page.tsx +36 -0
- package/templates/frontend/src/app/(dashboard)/layout.tsx +59 -0
- package/templates/frontend/src/app/globals.css +81 -0
- package/templates/frontend/src/app/layout.tsx +26 -0
- package/templates/frontend/src/app/page.tsx +5 -0
- package/templates/frontend/src/app/setup/page.tsx +278 -0
- package/templates/frontend/src/components/ui/button.tsx +52 -0
- package/templates/frontend/src/components/ui/card.tsx +50 -0
- package/templates/frontend/src/components/ui/form.tsx +158 -0
- package/templates/frontend/src/components/ui/input.tsx +21 -0
- package/templates/frontend/src/components/ui/label.tsx +22 -0
- package/templates/frontend/src/components/ui/toast.tsx +109 -0
- package/templates/frontend/src/components/ui/toaster.tsx +30 -0
- package/templates/frontend/src/hooks/use-toast.ts +116 -0
- package/templates/frontend/src/lib/api/auth.ts +39 -0
- package/templates/frontend/src/lib/api/client.ts +66 -0
- package/templates/frontend/src/lib/hooks/use-auth.ts +1 -0
- package/templates/frontend/src/lib/utils.ts +6 -0
- package/templates/frontend/src/providers/auth-provider.tsx +60 -0
- package/templates/frontend/src/types/api.ts +12 -0
- package/templates/frontend/src/types/auth.ts +27 -0
- package/templates/frontend/tsconfig.json +23 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<p align="center"><samp>
|
|
2
|
+
╔══════════════════════════════════╗<br/>
|
|
3
|
+
║ create-saas-ar-backend <br/>
|
|
4
|
+
║ AFIP · Mercado Pago · Auth · Mail <br/>
|
|
5
|
+
║ todo integrado en un comando <br/>
|
|
6
|
+
╚══════════════════════════════════╝<br/>
|
|
7
|
+
</samp></p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<strong>El backend SaaS que ojalá hubieras tenido cuando empezaste.</strong>
|
|
11
|
+
<br/>
|
|
12
|
+
AFIP, Mercado Pago, auth, multi-tenancy, emails — ya integrado. En vez de perder
|
|
13
|
+
3 semanas armando lo mismo de siempre, clonás esto y empezás a facturar.
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## ¿Por qué existe esto?
|
|
19
|
+
|
|
20
|
+
Armar un SaaS en Argentina duele. Pasás semanas cableando autenticación con JWT,
|
|
21
|
+
aislamiento multi-tenant, envío de mails, validaciones, estructura de carpetas,
|
|
22
|
+
manejo de errores. Y cuando por fin terminás todo ese boilerplate, te das cuenta
|
|
23
|
+
de que todavía falta integrar AFIP para facturación electrónica y Mercado Pago
|
|
24
|
+
para cobrar. Otras 2 semanas.
|
|
25
|
+
|
|
26
|
+
`create-saas-ar` genera este repositorio completo **en un comando**. Viene con
|
|
27
|
+
todo lo genérico ya resuelto, más integraciones reales para operar en Argentina.
|
|
28
|
+
**Solo tenés que agregar tus módulos de negocio** siguiendo el patrón de
|
|
29
|
+
`.ai-docs/`.
|
|
30
|
+
|
|
31
|
+
## Stack
|
|
32
|
+
|
|
33
|
+
| Capa | Tecnología | Versión |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| Runtime | Node.js | 22 LTS |
|
|
36
|
+
| Lenguaje | TypeScript | 5.7 |
|
|
37
|
+
| Framework | NestJS | 11 |
|
|
38
|
+
| Base de datos | MongoDB | 8 |
|
|
39
|
+
| ODM | Mongoose | 9 |
|
|
40
|
+
| Auth (tokens) | JWT + cookies HttpOnly | — |
|
|
41
|
+
| Auth (passwords) | bcrypt | 5.x |
|
|
42
|
+
| Auth (passport) | passport + passport-jwt | 0.7 / 4.x |
|
|
43
|
+
| Validación | class-validator | 0.14 |
|
|
44
|
+
| Transformación | class-transformer | 0.5 |
|
|
45
|
+
| Emails | Resend | 4.x |
|
|
46
|
+
| Documentación API | Swagger | 11.x |
|
|
47
|
+
| Tareas programadas | @nestjs/schedule | 6.x |
|
|
48
|
+
| Testing | Jest | 30 |
|
|
49
|
+
| Formateo | Prettier | 3.x |
|
|
50
|
+
| Linting | ESLint | 9.x |
|
|
51
|
+
|
|
52
|
+
## Características principales
|
|
53
|
+
|
|
54
|
+
- **Multi-tenancy real** — Aislamiento por `workspaceId` garantizado en cada query. Un `WorkspaceTenantInterceptor` extrae el tenant del header `x-workspace-id` o del JWT. `BaseRepository` fuerza el filtro en toda operación. Imposible leakear datos entre workspaces por error humano.
|
|
55
|
+
|
|
56
|
+
- **Auth completo** — Registro, login, refresh token rotativo, email verification, password reset, change password. Access + refresh tokens en cookies `HttpOnly`, `Secure`, `SameSite=Strict`. Nunca en `localStorage` ni en el body.
|
|
57
|
+
|
|
58
|
+
- **BaseRepository genérico** — Soft delete, paginación, filtros dinámicos, agregaciones, conteo, upsert. Manejo automático de errores MongoDB (duplicate key, cast error). 12 métodos heredados por todos los repositorios.
|
|
59
|
+
|
|
60
|
+
- **DTOs con validación estricta** — `class-validator` con mensajes en español. `class-transformer` para coerción de tipos. `PartialType` de Swagger para updates. `forbidNonWhitelisted` + `whitelist` para rechazar campos no declarados.
|
|
61
|
+
|
|
62
|
+
- **Manejo de errores uniforme** — `GlobalExceptionFilter` transforma toda excepción a `{ statusCode, message, error, timestamp, path }`. Errores 5xx se loguean, 4xx no. Mensajes de validación concatenados y en español.
|
|
63
|
+
|
|
64
|
+
- **Emails con Resend** — Servicio de mail con métodos para verificación, reset de contraseña y bienvenida. Templates HTML inline. Preparado para reintentos con `@nestjs/schedule` y cola de emails fallidos.
|
|
65
|
+
|
|
66
|
+
- **Swagger automático** — `@ApiProperty` y `@ApiTags` en cada DTO y controller. Documentación interactiva en `/api/docs` sin configuración extra.
|
|
67
|
+
|
|
68
|
+
- **Soporte multi-agente IA** — El proyecto incluye `.ai-docs/` (fuente de verdad compartida entre herramientas), `.claude/CLAUDE.md` (leído automáticamente por Claude Code) y `.opencode/` (prompt + config para OpenCode/DeepSeek). Cada herramienta tiene tareas asignadas según su fortaleza: Claude Code para arquitectura y decisiones de seguridad, DeepSeek para tareas mecánicas como generar CRUD o tests.
|
|
69
|
+
|
|
70
|
+
## Cómo empezar
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# 1. Clonar
|
|
74
|
+
git clone <repo-url> mi-saas-backend
|
|
75
|
+
cd mi-saas-backend
|
|
76
|
+
|
|
77
|
+
# 2. Instalar dependencias
|
|
78
|
+
npm install
|
|
79
|
+
|
|
80
|
+
# 3. Configurar variables de entorno
|
|
81
|
+
cp .env.example .env
|
|
82
|
+
# Editar .env con tus valores (MONGODB_URI, JWT secrets, RESEND_API_KEY, etc.)
|
|
83
|
+
|
|
84
|
+
# 4. Levantar en desarrollo
|
|
85
|
+
npm run start:dev
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
El servidor corre en `http://localhost:3000/api`. Swagger en `http://localhost:3000/api/docs`.
|
|
89
|
+
|
|
90
|
+
## Comandos disponibles
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm run start:dev # Desarrollo con hot reload
|
|
94
|
+
npm run start:prod # Producción (build + node dist/main)
|
|
95
|
+
npm run build # Compilar TypeScript
|
|
96
|
+
npm run test # Tests unitarios
|
|
97
|
+
npm run test:e2e # Tests end-to-end
|
|
98
|
+
npm run test:cov # Tests con coverage
|
|
99
|
+
npm run lint # ESLint con fix automático
|
|
100
|
+
npm run format # Prettier en todo el proyecto
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Estructura del proyecto
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
src/
|
|
107
|
+
├── common/
|
|
108
|
+
│ ├── base/
|
|
109
|
+
│ │ ├── base.schema.ts # workspaceId, createdBy, deletedAt
|
|
110
|
+
│ │ └── base.repository.ts # findAll, findById, create, update, softDelete, paginate, aggregate...
|
|
111
|
+
│ ├── decorators/
|
|
112
|
+
│ │ ├── workspace-id.decorator.ts # @WorkspaceId()
|
|
113
|
+
│ │ └── current-user.decorator.ts # @CurrentUser()
|
|
114
|
+
│ ├── filters/
|
|
115
|
+
│ │ └── global-exception.filter.ts # 4xx/5xx → { statusCode, message, error, timestamp, path }
|
|
116
|
+
│ ├── guards/
|
|
117
|
+
│ │ └── jwt-auth.guard.ts # AuthGuard('jwt')
|
|
118
|
+
│ └── interceptors/
|
|
119
|
+
│ └── workspace-tenant.interceptor.ts # x-workspace-id header → request.workspaceId
|
|
120
|
+
├── modules/
|
|
121
|
+
│ ├── auth/ # Registro, login, refresh, email verification, password reset
|
|
122
|
+
│ ├── users/ # CRUD de usuarios
|
|
123
|
+
│ ├── workspaces/ # CRUD de workspaces
|
|
124
|
+
│ └── mail/ # Envío de emails con Resend (@Global)
|
|
125
|
+
├── app.module.ts
|
|
126
|
+
└── main.ts # bootstrap: ValidationPipe, cookieParser, CORS, Swagger
|
|
127
|
+
.ai-docs/ # Documentación compartida entre agentes AI y desarrolladores
|
|
128
|
+
├── architecture/ # overview, module-pattern, database-pattern
|
|
129
|
+
├── conventions/ # naming, error-handling, dto-validation
|
|
130
|
+
├── modules/ # auth, multi-tenancy, mail
|
|
131
|
+
└── examples/ # full-module-example (módulo Clientes completo), repository-example
|
|
132
|
+
.claude/ # Prompt y reglas para Claude Code
|
|
133
|
+
.opencode/ # Prompt y config para OpenCode/DeepSeek
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Documentación para agentes AI
|
|
137
|
+
|
|
138
|
+
Este proyecto está diseñado para que dos agentes de IA trabajen en paralelo:
|
|
139
|
+
|
|
140
|
+
| Herramienta | Config | Ideal para |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| **Claude Code** | `.claude/CLAUDE.md` | Arquitectura, auth avanzado, decisiones de seguridad, refactors |
|
|
143
|
+
| **OpenCode / DeepSeek** | `.opencode/config.json` + `system-prompt.md` | CRUD de módulos nuevos, DTOs, tests, renombrar archivos |
|
|
144
|
+
|
|
145
|
+
Ambos leen `.ai-docs/` como fuente de verdad. Las **8 reglas absolutas** están en `.claude/CLAUDE.md` y `.opencode/system-prompt.md`.
|
|
146
|
+
|
|
147
|
+
## Cómo crear un módulo nuevo
|
|
148
|
+
|
|
149
|
+
Seguí el checklist de 12 pasos en `.ai-docs/examples/full-module-example.md`. El resumen:
|
|
150
|
+
|
|
151
|
+
1. Crear carpeta `src/modules/{nombre}/` con `schemas/` y `dto/`
|
|
152
|
+
2. Schema → extiende `BaseSchema`
|
|
153
|
+
3. DTO Create → `class-validator` con mensajes en español
|
|
154
|
+
4. DTO Update → `extends PartialType(CreateXxxDto)`
|
|
155
|
+
5. Repository → extiende `BaseRepository`, métodos con `workspaceId` primero
|
|
156
|
+
6. Service → `create`, `findAll`, `findById`, `update`, `remove`
|
|
157
|
+
7. Controller → `@WorkspaceId()`, `@CurrentUser()`, nunca `@Req()`
|
|
158
|
+
8. Module → `MongooseModule.forFeature(...)`, exporta el service
|
|
159
|
+
9. Registrar en `AppModule`
|
|
160
|
+
10. `npm run build` → verificar que compila
|
|
161
|
+
11. Swagger → verificar en `/api/docs`
|
|
162
|
+
12. Tests → unitarios del service, e2e del controller
|
|
163
|
+
|
|
164
|
+
El archivo `.ai-docs/examples/full-module-example.md` tiene el módulo Clientes completo para copiar y adaptar.
|
|
165
|
+
|
|
166
|
+
## Licencia
|
|
167
|
+
|
|
168
|
+
Privado (UNLICENSED). Generado con [`create-saas-ar`](https://github.com/anomalyco/create-saas-ar).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import eslint from '@eslint/js';
|
|
3
|
+
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
|
4
|
+
import globals from 'globals';
|
|
5
|
+
import tseslint from 'typescript-eslint';
|
|
6
|
+
|
|
7
|
+
export default tseslint.config(
|
|
8
|
+
{
|
|
9
|
+
ignores: ['eslint.config.mjs'],
|
|
10
|
+
},
|
|
11
|
+
eslint.configs.recommended,
|
|
12
|
+
...tseslint.configs.recommendedTypeChecked,
|
|
13
|
+
eslintPluginPrettierRecommended,
|
|
14
|
+
{
|
|
15
|
+
languageOptions: {
|
|
16
|
+
globals: {
|
|
17
|
+
...globals.node,
|
|
18
|
+
...globals.jest,
|
|
19
|
+
},
|
|
20
|
+
sourceType: 'commonjs',
|
|
21
|
+
parserOptions: {
|
|
22
|
+
projectService: true,
|
|
23
|
+
tsconfigRootDir: import.meta.dirname,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
rules: {
|
|
29
|
+
'@typescript-eslint/no-explicit-any': 'error',
|
|
30
|
+
'@typescript-eslint/no-floating-promises': 'warn',
|
|
31
|
+
'@typescript-eslint/no-unsafe-argument': 'warn',
|
|
32
|
+
'prettier/prettier': ['error', { endOfLine: 'auto' }],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
);
|