This commit is contained in:
92
DEPLOYMENT.md
Normal file
92
DEPLOYMENT.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
# Guía de Despliegue - Analítica Núcleo
|
||||||
|
|
||||||
|
Este proyecto se despliega automáticamente usando Gitea Actions en cada push a la rama `master`.
|
||||||
|
|
||||||
|
## Configuración en Gitea
|
||||||
|
|
||||||
|
### Secretos (Settings → Secrets)
|
||||||
|
|
||||||
|
Los siguientes secretos deben configurarse en el repositorio de Gitea:
|
||||||
|
|
||||||
|
| Secret | Descripción | Ejemplo |
|
||||||
|
|--------|-------------|---------|
|
||||||
|
| `SUPABASE_URL` | URL de tu instancia Supabase | `https://xxx.supabase.co` |
|
||||||
|
| `SUPABASE_ANON_KEY` | Clave anónima de Supabase | `eyJhbGc...` |
|
||||||
|
|
||||||
|
### Cómo agregar secretos en Gitea:
|
||||||
|
|
||||||
|
1. Ve a tu repositorio en Gitea
|
||||||
|
2. Navega a **Settings → Secrets**
|
||||||
|
3. Haz clic en **Add Secret**
|
||||||
|
4. Agrega cada uno de los secretos listados arriba
|
||||||
|
|
||||||
|
## Infraestructura
|
||||||
|
|
||||||
|
### Stack Docker
|
||||||
|
|
||||||
|
El proyecto se despliega como un stack de Docker Compose llamado `analiticanucleo` que contiene:
|
||||||
|
|
||||||
|
- **nuxt-app**: Aplicación Nuxt.js con SSR deshabilitado
|
||||||
|
|
||||||
|
### Traefik
|
||||||
|
|
||||||
|
La aplicación está configurada para usar Traefik como reverse proxy:
|
||||||
|
|
||||||
|
- **Dominio**: `analitica.nucleoriofrio.com`
|
||||||
|
- **Puerto interno**: `3000` (no expuesto públicamente)
|
||||||
|
- **TLS**: Habilitado con Let's Encrypt
|
||||||
|
- **Red**: `principal` (red externa compartida)
|
||||||
|
|
||||||
|
### Workflow de Despliegue
|
||||||
|
|
||||||
|
El workflow `.gitea/workflows/deploy.yml` se ejecuta automáticamente en cada push a `master` y:
|
||||||
|
|
||||||
|
1. Crea el archivo `.env` con los secretos
|
||||||
|
2. Verifica/crea la red Docker `principal`
|
||||||
|
3. Detiene el stack existente (si existe)
|
||||||
|
4. Construye la nueva imagen Docker
|
||||||
|
5. Inicia el stack actualizado
|
||||||
|
6. Muestra logs y estado de los servicios
|
||||||
|
|
||||||
|
## Archivos del Proyecto
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── Dockerfile # Imagen Docker multi-stage con Node 22
|
||||||
|
├── docker-compose.yml # Configuración del stack con labels de Traefik
|
||||||
|
├── .gitea/workflows/deploy.yml # Workflow de CI/CD
|
||||||
|
└── nuxt4-app/ # Código de la aplicación Nuxt
|
||||||
|
├── nuxt.config.ts # Configuración de Nuxt (ssr: false)
|
||||||
|
└── nuxt.config.workaround.ts # Workaround para @nuxt/ui v4 con ssr: false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notas Técnicas
|
||||||
|
|
||||||
|
### Workaround para @nuxt/ui v4
|
||||||
|
|
||||||
|
Debido a un issue conocido con `@nuxt/ui` v4 y `ssr: false`, se implementó un plugin de Vite (`nuxt.config.workaround.ts`) que marca como externos los módulos de servidor (`@nuxt/kit`, `@tailwindcss/*`, etc.) para evitar que se incluyan en el bundle del cliente.
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
El build utiliza:
|
||||||
|
- Node.js 22 Alpine
|
||||||
|
- Vite 7
|
||||||
|
- Nuxt 4
|
||||||
|
- Sharp para procesamiento de imágenes
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### El build falla con errores de importación
|
||||||
|
|
||||||
|
Asegúrate de que el archivo `nuxt.config.workaround.ts` está presente y correctamente importado en `nuxt.config.ts`.
|
||||||
|
|
||||||
|
### La aplicación no es accesible
|
||||||
|
|
||||||
|
1. Verifica que Traefik esté corriendo
|
||||||
|
2. Verifica que la red `principal` existe: `docker network ls`
|
||||||
|
3. Verifica los logs del contenedor: `docker logs analiticanucleo-nuxt-app`
|
||||||
|
4. Verifica las labels de Traefik: `docker inspect analiticanucleo-nuxt-app`
|
||||||
|
|
||||||
|
### Variables de entorno no se aplican
|
||||||
|
|
||||||
|
Verifica que los secretos estén configurados correctamente en Gitea y que el workflow los esté pasando al archivo `.env`.
|
||||||
@@ -3,6 +3,9 @@ FROM node:22-alpine AS builder
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install build dependencies for sharp
|
||||||
|
RUN apk add --no-cache python3 make g++ vips-dev
|
||||||
|
|
||||||
# Copy package files
|
# Copy package files
|
||||||
COPY nuxt4-app/package*.json ./
|
COPY nuxt4-app/package*.json ./
|
||||||
|
|
||||||
@@ -20,6 +23,9 @@ FROM node:22-alpine
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install runtime dependencies for sharp
|
||||||
|
RUN apk add --no-cache vips
|
||||||
|
|
||||||
# Copy built application from builder
|
# Copy built application from builder
|
||||||
COPY --from=builder /app/.output /app/.output
|
COPY --from=builder /app/.output /app/.output
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
|
import { disableImportProtection } from './nuxt.config.workaround'
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
ssr: false,
|
ssr: false,
|
||||||
compatibilityDate: '2025-07-15',
|
compatibilityDate: '2025-07-15',
|
||||||
@@ -14,6 +16,7 @@ export default defineNuxtConfig({
|
|||||||
|
|
||||||
// Optimize build
|
// Optimize build
|
||||||
vite: {
|
vite: {
|
||||||
|
plugins: [disableImportProtection()],
|
||||||
build: {
|
build: {
|
||||||
cssCodeSplit: true,
|
cssCodeSplit: true,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
|
|||||||
31
nuxt4-app/nuxt.config.workaround.ts
Normal file
31
nuxt4-app/nuxt.config.workaround.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// Workaround for @nuxt/ui v4 import protection issue
|
||||||
|
// This is a temporary fix until @nuxt/ui properly handles ssr: false
|
||||||
|
|
||||||
|
import type { Plugin } from 'vite'
|
||||||
|
|
||||||
|
export function disableImportProtection(): Plugin {
|
||||||
|
return {
|
||||||
|
name: 'disable-import-protection-for-nuxt-ui',
|
||||||
|
enforce: 'pre',
|
||||||
|
resolveId(id, importer) {
|
||||||
|
// External node binary files
|
||||||
|
if (id.endsWith('.node')) {
|
||||||
|
return { id, external: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
// External Node.js built-in modules
|
||||||
|
const nodeModules = ['fs', 'path', 'url', 'fs/promises', 'node:url', 'node:module', 'node:fs', 'node:path']
|
||||||
|
if (nodeModules.includes(id) || id.startsWith('node:')) {
|
||||||
|
return { id, external: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
// External server-only packages from @nuxt/ui imports
|
||||||
|
const serverPackages = ['@nuxt/kit', '@tailwindcss/node', '@tailwindcss/oxide', 'jiti']
|
||||||
|
for (const pkg of serverPackages) {
|
||||||
|
if (id === pkg || id.startsWith(pkg + '/')) {
|
||||||
|
return { id, external: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user