Guía de setup
Requisitos, variables de entorno y primer arranque, con comandos listos para copiar y pegar.
Esta guía te deja el template corriendo en local, con la base de datos migrada y una cuenta con la que entrar. Todo se ejecuta con pnpm, que es el gestor fijado en packageManager dentro de package.json.
pnpm install instala también los hooks de git: en cada commit corre ESLint sobre lo que esté en stage (segundos) y en cada push la suite completa de Playwright. Para saltar la suite de forma deliberada existe SKIP_E2E=1 git push.Requisitos
| Herramienta | Versión | Para qué |
|---|---|---|
| Node.js | >= 22.12 | El runtime fijado en package.json → engines |
| pnpm | 10.x | Gestor de paquetes; actívalo con corepack enable |
| PostgreSQL | 15 o superior | Base de datos. Sirve una gratuita de Neon o una local |
1. Instala las dependencias
pnpm install
2. Configura el entorno
Crea un .env en la raíz del proyecto. Estas son las variables que necesitas para arrancar:
# Base de datos PostgreSQL (usa la connection string completa)
NUXT_DATABASE_URL="postgresql://usuario:password@host:5432/base?sslmode=require"
# Better Auth: cadena larga y aleatoria, distinta en cada entorno
BETTER_AUTH_SECRET="pega-aqui-un-secreto-largo"
# URL pública de la app (Better Auth la usa como baseURL)
NUXT_APP_URL="http://localhost:3000"
# Email del administrador de la instancia: con la tabla `user` vacía, `/setup`
# solo acepta esta dirección para crear la primera cuenta (paso 4).
NUXT_ADMIN_EMAIL="admin@example.com"
# Opcional: solo la usa la tarea no interactiva `db:seed_admin`. La contraseña
# normal se elige en `/setup`, no en el entorno.
NUXT_ADMIN_PASSWORD="una-password-larga"
El archivo .env.example de la raíz es la plantilla comentada: cópialo a .env y completa los valores. server/utils/runtimeConfig.ts es la fuente de verdad de los nombres.
Obligatorias
| Variable | Para qué | Dónde se lee |
|---|---|---|
NUXT_DATABASE_URL | Connection string de PostgreSQL | server/utils/db.ts, server/utils/pgboss.ts, server/database/drizzle.config.ts |
BETTER_AUTH_SECRET | Firma de sesiones, magic links y tokens | Better Auth la toma del entorno (fallback del SDK); alternativa NUXT_BETTER_AUTH_SECRET → runtimeConfig.betterAuthSecret (server/utils/auth.ts, secret) |
NUXT_APP_URL | Origen público: baseURL y trustedOrigins de Better Auth, enlaces de invitación y exportaciones, baseUrl de i18n | nuxt.config.ts, server/utils/auth.ts, server/utils/invitations.ts |
NUXT_ADMIN_EMAIL | Email del administrador: es la única dirección que /setup acepta para crear la primera cuenta | server/api/setup/* |
NUXT_ADMIN_PASSWORD | Opcional — solo la tarea no interactiva db:seed_admin | server/tasks/db/seed_admin.ts |
Opcionales
| Variable | Para qué y sin ella | Dónde se lee |
|---|---|---|
NUXT_NITRO_PRESET | Preset de Nitro; con node-server (el del repo) el pool de Drizzle se cachea por proceso | server/utils/db.ts |
NUXT_DB_POOL_MAX · _IDLE_TIMEOUT · _CONNECT_TIMEOUT · _MAX_LIFETIME | Ajuste del pool de postgres-js (segundos); sin ellas, 10 conexiones y timeouts 20/10/1800 s | server/utils/db.ts |
NUXT_REDIS_URL | Redis como almacenamiento secundario de Better Auth; sin ella (o si Redis cae) todo va contra la base de datos | server/utils/secondary-storage.ts, server/api/admin/system/health.get.ts |
NUXT_RESEND_API_KEY | Correos transaccionales; sin clave se registran pero no se envían | server/utils/mails-templates.ts, server/api/admin/system/health.get.ts |
NUXT_APP_NAME | Nombre visible en correos y comunicaciones (el de la interfaz sale de i18n) | server/utils/mails-templates.ts, server/emails/communication.ts |
NUXT_APP_NOTIFY_EMAIL | Remitente From de los correos | server/utils/mails-templates.ts |
NUXT_APP_S3_ENDPOINT · _REGION · _ACCESS_KEY · _SECRET_KEY · _BUCKET_NAME | Documentos, fotos y adjuntos; sin ellas las subidas quedan apagadas (región por defecto us-east-1) | server/utils/create-s3-client.ts, server/utils/get-presigned.ts, server/api/upload/*, server/api/admin/system/health.get.ts |
NUXT_APP_S3_BACKUP_BUCKET_NAME | Bucket dedicado a los backups de base de datos del dashboard admin; sin él los backups quedan apagados (requiere la sección S3 de arriba) | server/utils/database-backup.ts, server/api/admin/backups/*, server/api/admin/system/health.get.ts |
NUXT_BACKUP_DATABASE_URL · NUXT_BACKUP_PG_DUMP_PATH | Backups: conexión directa para pg_dump (si la principal es pooled) y ruta del binario; sin ellas se usa NUXT_DATABASE_URL quitándole -pooler y el pg_dump del PATH | server/utils/database-backup.ts |
NUXT_APP_GOOGLE_CLIENT_ID · NUXT_APP_GOOGLE_CLIENT_SECRET | Login con Google; sin claves el proveedor solo emite un warning al arrancar | server/utils/auth.ts |
NUXT_GOOGLE_MAPS_SERVER_KEY | Geocodificación en el servidor (autocomplete, place details, timezone) | server/api/google/*.get.ts |
NUXT_PUBLIC_GOOGLE_MAPS_CLIENT_KEY | Key pública del selector de ubicación (restringida por referrer) | app/components/plan/LocationPicker.vue |
/app/admin/dashboard) necesitan además el binario pg_dump (versión ≥ a la del servidor PostgreSQL) en la máquina que corre la app: en local brew install postgresql@17 o apt install postgresql-client-17; en el deploy lo instala el Dockerfile.runtimeConfig lee algunas variables que hoy no tienen consumidores, así que no hacen falta para arrancar: BETTER_AUTH_URL (el baseURL sale de NUXT_APP_URL), NUXT_RESEND_WEBHOOK_SECRET, NUXT_ADMIN_USER_IDS, NUXT_APP_CONTACT_EMAIL, NODE_ENV (public.appEnv) y NUXT_PUBLIC_SITE_URL.BETTER_AUTH_SECRET local, el de dev y el de producción deben ser distintos. Ese secreto firma sesiones y enlaces mágicos: si se filtra, hay que rotarlo y todos los enlaces pendientes dejan de valer.3. Migra la base de datos
pnpm db:migrate # aplica las migraciones pendientes
pnpm db:generate # genera una migración después de cambiar el schema
pnpm studio # abre Drizzle Studio para inspeccionar datos
4. Crea la cuenta admin
El template no tiene registro público. La primera cuenta se crea desde la pantalla de
setup de primer arranque: arranca el servidor y abre http://localhost:3000/setup
(con la app en marcha, cualquier visita a una ruta privada te lleva ahí mientras no exista
ningún usuario).
La pantalla pide el email y la contraseña. El email tiene que coincidir con
NUXT_ADMIN_EMAIL — el servidor rechaza cualquier otro, así que funciona como el secreto
de la instalación — y la contraseña la eliges tú en ese momento. La cuenta que se crea es
platform admin, queda verificada y se inicia sesión automáticamente.
La pantalla deja de existir en cuanto hay un usuario: /setup redirige al login.
Alternativa no interactiva. Para un deploy automatizado,
db:seed_admincrea la cuenta a partir deNUXT_ADMIN_EMAILyNUXT_ADMIN_PASSWORDdel entorno. Con el servidor corriendo:curl -X POST http://localhost:3000/_nitro/tasks/db:seed_adminLa tarea es idempotente: si el usuario ya existe, no hace nada. La lista completa de tareas está en
GET /_nitro/tasks.
Esa cuenta es también la que usa la suite de Playwright (E2E_EMAIL / E2E_PASSWORD, con
las credenciales del seed como fallback).
5. Arranca
pnpm dev # http://localhost:3000
pnpm test:e2e:smoke # smoke de Playwright sobre las páginas principales
pnpm lint # ESLint (es el único formatter del repo)
Siguientes pasos
- Ramas y flujo de trabajo: cómo crear una feature, un fix o un hotfix.
- Design system: los tokens, las clases
.ds-*y las reglas de UI. - Deploy y CI/CD: Dokploy, entornos y migraciones.