ar-saas 0.3.0 → 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.
- package/LICENSE +21 -21
- package/README.md +338 -314
- package/dist/cli.js +19 -0
- package/dist/generator.js +166 -55
- package/package.json +52 -50
- package/templates/backend/.env.example +67 -67
- package/templates/backend/.prettierrc +4 -4
- package/templates/backend/README.md +249 -168
- package/templates/backend/eslint.config.mjs +35 -35
- package/templates/backend/nest-cli.json +8 -8
- package/templates/backend/package-lock.json +10979 -10979
- package/templates/backend/package.json +88 -88
- package/templates/backend/src/app.controller.spec.ts +24 -24
- package/templates/backend/src/app.controller.ts +15 -15
- package/templates/backend/src/app.module.ts +40 -40
- package/templates/backend/src/app.service.ts +11 -11
- package/templates/backend/src/common/base/base.repository.ts +221 -221
- package/templates/backend/src/common/base/base.schema.ts +24 -24
- package/templates/backend/src/common/decorators/cookie.decorator.ts +9 -9
- package/templates/backend/src/common/decorators/current-user.decorator.ts +20 -20
- package/templates/backend/src/common/decorators/workspace-id.decorator.ts +14 -14
- package/templates/backend/src/common/filters/global-exception.filter.ts +61 -61
- package/templates/backend/src/common/guards/jwt-auth.guard.ts +5 -5
- package/templates/backend/src/common/interceptors/workspace-tenant.interceptor.ts +45 -45
- package/templates/backend/src/main.ts +51 -51
- package/templates/backend/src/modules/auth/auth.controller.ts +158 -158
- package/templates/backend/src/modules/auth/auth.module.ts +20 -20
- package/templates/backend/src/modules/auth/auth.service.ts +257 -257
- package/templates/backend/src/modules/auth/dto/forgot-password.dto.ts +9 -9
- package/templates/backend/src/modules/auth/dto/login.dto.ts +14 -14
- package/templates/backend/src/modules/auth/dto/refresh-token.dto.ts +12 -12
- package/templates/backend/src/modules/auth/dto/register.dto.ts +26 -26
- package/templates/backend/src/modules/auth/dto/reset-password.dto.ts +16 -16
- package/templates/backend/src/modules/auth/dto/verify-email.dto.ts +9 -9
- package/templates/backend/src/modules/auth/strategies/jwt.strategy.ts +43 -43
- package/templates/backend/src/modules/mail/mail.module.ts +9 -9
- package/templates/backend/src/modules/mail/mail.service.ts +141 -141
- package/templates/backend/src/modules/users/schemas/user.schema.ts +54 -54
- package/templates/backend/src/modules/users/users.module.ts +14 -14
- package/templates/backend/src/modules/users/users.repository.ts +51 -51
- package/templates/backend/src/modules/users/users.service.ts +104 -104
- package/templates/backend/src/modules/workspaces/schemas/workspace.schema.ts +26 -26
- package/templates/backend/src/modules/workspaces/workspaces.module.ts +16 -16
- package/templates/backend/src/modules/workspaces/workspaces.repository.ts +34 -34
- package/templates/backend/src/modules/workspaces/workspaces.service.ts +42 -42
- package/templates/backend/test/app.e2e-spec.ts +25 -25
- package/templates/backend/test/jest-e2e.json +9 -9
- package/templates/backend/tsconfig.build.json +4 -4
- package/templates/backend/tsconfig.json +26 -26
- package/templates/frontend/.env.local.example +1 -1
- package/templates/frontend/README.md +152 -0
- package/templates/frontend/components.json +20 -20
- package/templates/frontend/eslint.config.mjs +14 -14
- package/templates/frontend/next.config.ts +5 -5
- package/templates/frontend/package-lock.json +6722 -6722
- package/templates/frontend/package.json +48 -48
- package/templates/frontend/pnpm-lock.yaml +5012 -5012
- package/templates/frontend/pnpm-workspace.yaml +3 -3
- package/templates/frontend/postcss.config.mjs +7 -7
- package/templates/frontend/src/app/(auth)/forgot-password/page.tsx +84 -84
- package/templates/frontend/src/app/(auth)/layout.tsx +28 -28
- package/templates/frontend/src/app/(auth)/login/page.tsx +111 -111
- package/templates/frontend/src/app/(auth)/register/page.tsx +161 -161
- package/templates/frontend/src/app/(auth)/reset-password/page.tsx +120 -120
- package/templates/frontend/src/app/(auth)/verify-email/page.tsx +78 -78
- package/templates/frontend/src/app/(dashboard)/billing/page.tsx +111 -111
- package/templates/frontend/src/app/(dashboard)/dashboard/page.tsx +105 -105
- package/templates/frontend/src/app/(dashboard)/layout.tsx +38 -38
- package/templates/frontend/src/app/(dashboard)/profile/page.tsx +226 -226
- package/templates/frontend/src/app/(dashboard)/settings/page.tsx +156 -156
- package/templates/frontend/src/app/(dashboard)/team/page.tsx +178 -178
- package/templates/frontend/src/app/(legal)/privacy/page.tsx +127 -127
- package/templates/frontend/src/app/(legal)/terms/page.tsx +118 -118
- package/templates/frontend/src/app/globals.css +81 -81
- package/templates/frontend/src/app/layout.tsx +26 -26
- package/templates/frontend/src/app/page.tsx +5 -45
- package/templates/frontend/src/app/setup/page.tsx +371 -275
- package/templates/frontend/src/components/dashboard/header.tsx +89 -89
- package/templates/frontend/src/components/dashboard/sidebar.tsx +71 -71
- package/templates/frontend/src/components/dashboard/stat-card.tsx +34 -34
- package/templates/frontend/src/components/landing/faq.tsx +39 -39
- package/templates/frontend/src/components/landing/features.tsx +54 -54
- package/templates/frontend/src/components/landing/footer.tsx +76 -76
- package/templates/frontend/src/components/landing/hero.tsx +72 -72
- package/templates/frontend/src/components/landing/navbar.tsx +78 -78
- package/templates/frontend/src/components/landing/pricing.tsx +90 -90
- package/templates/frontend/src/components/ui/accordion.tsx +52 -52
- package/templates/frontend/src/components/ui/avatar.tsx +46 -46
- package/templates/frontend/src/components/ui/badge.tsx +30 -30
- package/templates/frontend/src/components/ui/button.tsx +52 -52
- package/templates/frontend/src/components/ui/card.tsx +50 -50
- package/templates/frontend/src/components/ui/checkbox.tsx +27 -27
- package/templates/frontend/src/components/ui/dialog.tsx +100 -100
- package/templates/frontend/src/components/ui/dropdown-menu.tsx +173 -173
- package/templates/frontend/src/components/ui/form.tsx +158 -158
- package/templates/frontend/src/components/ui/input.tsx +21 -21
- package/templates/frontend/src/components/ui/label.tsx +22 -22
- package/templates/frontend/src/components/ui/separator.tsx +25 -25
- package/templates/frontend/src/components/ui/skeleton.tsx +7 -7
- package/templates/frontend/src/components/ui/switch.tsx +28 -28
- package/templates/frontend/src/components/ui/tabs.tsx +54 -54
- package/templates/frontend/src/components/ui/textarea.tsx +20 -20
- package/templates/frontend/src/components/ui/toast.tsx +109 -109
- package/templates/frontend/src/components/ui/toaster.tsx +30 -30
- package/templates/frontend/src/config/site.ts +197 -197
- package/templates/frontend/src/hooks/use-toast.ts +116 -116
- package/templates/frontend/src/lib/api/auth.ts +39 -39
- package/templates/frontend/src/lib/api/client.ts +66 -66
- package/templates/frontend/src/lib/hooks/use-auth.ts +1 -1
- package/templates/frontend/src/lib/utils.ts +6 -6
- package/templates/frontend/src/providers/auth-provider.tsx +60 -60
- package/templates/frontend/src/types/api.ts +12 -12
- package/templates/frontend/src/types/auth.ts +27 -27
- package/templates/frontend/tsconfig.json +23 -23
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"module": "nodenext",
|
|
4
|
-
"moduleResolution": "nodenext",
|
|
5
|
-
"resolvePackageJsonExports": true,
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"isolatedModules": true,
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"removeComments": true,
|
|
10
|
-
"emitDecoratorMetadata": true,
|
|
11
|
-
"experimentalDecorators": true,
|
|
12
|
-
"allowSyntheticDefaultImports": true,
|
|
13
|
-
"target": "ES2023",
|
|
14
|
-
"sourceMap": true,
|
|
15
|
-
"outDir": "./dist",
|
|
16
|
-
"baseUrl": "./",
|
|
17
|
-
"incremental": true,
|
|
18
|
-
"skipLibCheck": true,
|
|
19
|
-
"strict": true,
|
|
20
|
-
"forceConsistentCasingInFileNames": true,
|
|
21
|
-
"noImplicitAny": true,
|
|
22
|
-
"strictNullChecks": true,
|
|
23
|
-
"strictBindCallApply": true,
|
|
24
|
-
"noFallthroughCasesInSwitch": true
|
|
25
|
-
}
|
|
26
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "nodenext",
|
|
4
|
+
"moduleResolution": "nodenext",
|
|
5
|
+
"resolvePackageJsonExports": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"isolatedModules": true,
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"removeComments": true,
|
|
10
|
+
"emitDecoratorMetadata": true,
|
|
11
|
+
"experimentalDecorators": true,
|
|
12
|
+
"allowSyntheticDefaultImports": true,
|
|
13
|
+
"target": "ES2023",
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"outDir": "./dist",
|
|
16
|
+
"baseUrl": "./",
|
|
17
|
+
"incremental": true,
|
|
18
|
+
"skipLibCheck": true,
|
|
19
|
+
"strict": true,
|
|
20
|
+
"forceConsistentCasingInFileNames": true,
|
|
21
|
+
"noImplicitAny": true,
|
|
22
|
+
"strictNullChecks": true,
|
|
23
|
+
"strictBindCallApply": true,
|
|
24
|
+
"noFallthroughCasesInSwitch": true
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
NEXT_PUBLIC_API_URL=http://localhost:3000
|
|
1
|
+
NEXT_PUBLIC_API_URL=http://localhost:3000
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# create-saas-ar — Frontend
|
|
2
|
+
|
|
3
|
+
Frontend del template SaaS para startups argentinas. Stack: Next.js 15, TypeScript, Tailwind CSS 4, shadcn/ui.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Stack
|
|
8
|
+
|
|
9
|
+
| Capa | Tecnología |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Framework | Next.js 15 (App Router) |
|
|
12
|
+
| Lenguaje | TypeScript (strict) |
|
|
13
|
+
| Estilos | Tailwind CSS 4 |
|
|
14
|
+
| Componentes UI | shadcn/ui |
|
|
15
|
+
| Formularios | react-hook-form |
|
|
16
|
+
| HTTP | axios (con interceptor de refresh automático) |
|
|
17
|
+
| Auth | Cookies HttpOnly — tokens manejados por el backend |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Prerequisitos
|
|
22
|
+
|
|
23
|
+
- Node.js 20 LTS o superior
|
|
24
|
+
- El backend corriendo en `http://localhost:3000` (o la URL configurada en `NEXT_PUBLIC_API_URL`)
|
|
25
|
+
- MongoDB corriendo (ver instrucciones en el README del backend)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Setup inicial
|
|
30
|
+
|
|
31
|
+
### 1. Instalar dependencias
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cd frontend
|
|
35
|
+
npm install
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. Configurar variables de entorno
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# El generador ya copió .env.local.example → .env.local automáticamente
|
|
42
|
+
# Solo verificar que el valor sea correcto:
|
|
43
|
+
cat .env.local
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
| Variable | Descripción | Valor por defecto |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `NEXT_PUBLIC_API_URL` | URL base del backend | `http://localhost:3000` |
|
|
49
|
+
|
|
50
|
+
Si cambiaste el puerto del backend, actualizá este valor.
|
|
51
|
+
|
|
52
|
+
### 3. Levantar el backend primero
|
|
53
|
+
|
|
54
|
+
El frontend depende del backend para autenticación. Antes de arrancar el frontend, asegurate de que el backend esté corriendo:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# En otra terminal
|
|
58
|
+
cd backend
|
|
59
|
+
npm run start:dev
|
|
60
|
+
# Verificar: http://localhost:3000/api/docs debe cargar
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Para levantar MongoDB antes del backend, ver las instrucciones en `backend/README.md` o ejecutar:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Desde la raíz del proyecto
|
|
67
|
+
docker compose -f docker-compose.dev.yml up -d
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 4. Iniciar el frontend
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm run dev
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
El frontend levanta en `http://localhost:3001`. Al abrirlo por primera vez verás la pantalla de setup con instrucciones paso a paso.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Comandos disponibles
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm run dev # Servidor de desarrollo con hot reload
|
|
84
|
+
npm run build # Build de producción
|
|
85
|
+
npm run start # Servidor de producción (requiere build previo)
|
|
86
|
+
npm run lint # ESLint
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Estructura de carpetas
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
src/
|
|
95
|
+
├── app/
|
|
96
|
+
│ ├── (auth)/ # Login, registro, verificación de email, reset de contraseña
|
|
97
|
+
│ ├── (dashboard)/ # Rutas protegidas (dashboard, perfil, billing, equipo)
|
|
98
|
+
│ ├── (legal)/ # Términos y privacidad
|
|
99
|
+
│ ├── setup/ # Pantalla de setup inicial (se muestra al arrancar por primera vez)
|
|
100
|
+
│ ├── layout.tsx # Layout raíz con AuthProvider
|
|
101
|
+
│ └── page.tsx # Redirige a /setup
|
|
102
|
+
├── components/
|
|
103
|
+
│ ├── landing/ # Componentes de la landing page (navbar, hero, features, pricing)
|
|
104
|
+
│ ├── dashboard/ # Sidebar, header y cards del dashboard
|
|
105
|
+
│ └── ui/ # Componentes shadcn/ui (no modificar directamente)
|
|
106
|
+
├── config/
|
|
107
|
+
│ └── site.ts # Configuración centralizada de contenido del sitio
|
|
108
|
+
├── lib/
|
|
109
|
+
│ ├── api/
|
|
110
|
+
│ │ ├── client.ts # Instancia axios con interceptor de 401 → refresh automático
|
|
111
|
+
│ │ └── auth.ts # Métodos de API de autenticación
|
|
112
|
+
│ └── hooks/
|
|
113
|
+
│ └── use-auth.ts # Hook para acceder al estado de auth
|
|
114
|
+
├── providers/
|
|
115
|
+
│ └── auth-provider.tsx # Contexto global de auth (login, logout, register, estado)
|
|
116
|
+
└── types/ # Interfaces TypeScript (User, Workspace, ApiError, etc.)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Personalizar el contenido del sitio
|
|
122
|
+
|
|
123
|
+
Todo el contenido de la landing page (nombre, tagline, features, precios, FAQ) está centralizado en [`src/config/site.ts`](src/config/site.ts).
|
|
124
|
+
|
|
125
|
+
Los valores con formato `__PLACEHOLDER__` son reemplazados automáticamente por el generador al crear el proyecto. Para personalizarlos manualmente:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
// src/config/site.ts
|
|
129
|
+
export const siteConfig = {
|
|
130
|
+
name: 'Mi SaaS',
|
|
131
|
+
tagline: 'La descripción corta de tu producto',
|
|
132
|
+
description: 'Descripción larga para SEO',
|
|
133
|
+
supportEmail: 'soporte@midominio.com',
|
|
134
|
+
// ... pricing, features, FAQ, etc.
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Rutas protegidas
|
|
141
|
+
|
|
142
|
+
Las rutas bajo `(dashboard)/` requieren autenticación. Si el usuario no está logueado, es redirigido a `/login` automáticamente (manejado en el layout del grupo, sin middleware).
|
|
143
|
+
|
|
144
|
+
Para agregar nuevas rutas protegidas, crear la carpeta dentro de `src/app/(dashboard)/`.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Autenticación
|
|
149
|
+
|
|
150
|
+
- Tokens JWT en cookies HttpOnly — el frontend nunca lee ni guarda tokens.
|
|
151
|
+
- `useAuth()` expone `user`, `isAuthenticated`, `isLoading`, `login()`, `logout()`, `register()`.
|
|
152
|
+
- El cliente axios renueva el access token automáticamente cuando recibe un 401.
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
-
"style": "default",
|
|
4
|
-
"rsc": true,
|
|
5
|
-
"tsx": true,
|
|
6
|
-
"tailwind": {
|
|
7
|
-
"config": "",
|
|
8
|
-
"css": "src/app/globals.css",
|
|
9
|
-
"baseColor": "slate",
|
|
10
|
-
"cssVariables": true
|
|
11
|
-
},
|
|
12
|
-
"aliases": {
|
|
13
|
-
"components": "@/components",
|
|
14
|
-
"utils": "@/lib/utils",
|
|
15
|
-
"ui": "@/components/ui",
|
|
16
|
-
"lib": "@/lib",
|
|
17
|
-
"hooks": "@/hooks"
|
|
18
|
-
},
|
|
19
|
-
"iconLibrary": "lucide"
|
|
20
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "default",
|
|
4
|
+
"rsc": true,
|
|
5
|
+
"tsx": true,
|
|
6
|
+
"tailwind": {
|
|
7
|
+
"config": "",
|
|
8
|
+
"css": "src/app/globals.css",
|
|
9
|
+
"baseColor": "slate",
|
|
10
|
+
"cssVariables": true
|
|
11
|
+
},
|
|
12
|
+
"aliases": {
|
|
13
|
+
"components": "@/components",
|
|
14
|
+
"utils": "@/lib/utils",
|
|
15
|
+
"ui": "@/components/ui",
|
|
16
|
+
"lib": "@/lib",
|
|
17
|
+
"hooks": "@/hooks"
|
|
18
|
+
},
|
|
19
|
+
"iconLibrary": "lucide"
|
|
20
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { dirname } from 'path'
|
|
2
|
-
import { fileURLToPath } from 'url'
|
|
3
|
-
import { FlatCompat } from '@eslint/eslintrc'
|
|
4
|
-
|
|
5
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
6
|
-
const __dirname = dirname(__filename)
|
|
7
|
-
|
|
8
|
-
const compat = new FlatCompat({ baseDirectory: __dirname })
|
|
9
|
-
|
|
10
|
-
const eslintConfig = [
|
|
11
|
-
...compat.extends('next/core-web-vitals', 'next/typescript'),
|
|
12
|
-
]
|
|
13
|
-
|
|
14
|
-
export default eslintConfig
|
|
1
|
+
import { dirname } from 'path'
|
|
2
|
+
import { fileURLToPath } from 'url'
|
|
3
|
+
import { FlatCompat } from '@eslint/eslintrc'
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
6
|
+
const __dirname = dirname(__filename)
|
|
7
|
+
|
|
8
|
+
const compat = new FlatCompat({ baseDirectory: __dirname })
|
|
9
|
+
|
|
10
|
+
const eslintConfig = [
|
|
11
|
+
...compat.extends('next/core-web-vitals', 'next/typescript'),
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
export default eslintConfig
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { NextConfig } from 'next'
|
|
2
|
-
|
|
3
|
-
const nextConfig: NextConfig = {}
|
|
4
|
-
|
|
5
|
-
export default nextConfig
|
|
1
|
+
import type { NextConfig } from 'next'
|
|
2
|
+
|
|
3
|
+
const nextConfig: NextConfig = {}
|
|
4
|
+
|
|
5
|
+
export default nextConfig
|