production: docker + nginx config for rf-flux.com
Deploy to VPS / deploy (push) Has been cancelled

This commit is contained in:
2026-03-20 13:46:05 -05:00
parent b275b19f08
commit fc24313f15
187 changed files with 20977 additions and 767 deletions
BIN
View File
Binary file not shown.
@@ -0,0 +1,214 @@
-- CreateSchema
CREATE SCHEMA IF NOT EXISTS "public";
-- CreateTable
CREATE TABLE "AdminUser" (
"id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"email" TEXT,
"passwordHash" TEXT NOT NULL,
"twoFactorSecret" TEXT,
"is2FAEnabled" BOOLEAN NOT NULL DEFAULT false,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "AdminUser_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "GlobalNode" (
"id" TEXT NOT NULL,
"title" TEXT NOT NULL,
"location" TEXT NOT NULL,
"lat" DOUBLE PRECISION NOT NULL,
"lon" DOUBLE PRECISION NOT NULL,
"nodeType" TEXT NOT NULL DEFAULT 'installation',
"application" TEXT NOT NULL,
"stats" TEXT NOT NULL,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"projectOverview" TEXT,
"energySavings" TEXT,
"eventDate" TIMESTAMP(3),
"mediaFileName" TEXT,
"galleryJson" TEXT DEFAULT '[]',
"videosJson" TEXT DEFAULT '[]',
"specificDatasheetJson" TEXT DEFAULT '[]',
"model3DPath" TEXT,
"rendersJson" TEXT DEFAULT '[]',
"model3DDimsJson" TEXT,
"translationsJson" TEXT DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "GlobalNode_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Application" (
"id" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"title" TEXT NOT NULL,
"subtitle" TEXT NOT NULL,
"category" TEXT NOT NULL,
"shortDescription" TEXT NOT NULL DEFAULT 'Learn more about this FLUX RF technology application.',
"heroDescription" TEXT NOT NULL,
"sectionsJson" TEXT NOT NULL,
"advantagesJson" TEXT NOT NULL,
"datasheetJson" TEXT NOT NULL,
"dashboardMetricsJson" TEXT DEFAULT '[]',
"isActive" BOOLEAN NOT NULL DEFAULT true,
"translationsJson" TEXT DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Application_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "TimelineEvent" (
"id" TEXT NOT NULL,
"year" TEXT NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"order" INTEGER NOT NULL DEFAULT 0,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"translationsJson" TEXT DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "TimelineEvent_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "NewsArticle" (
"id" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"title" TEXT NOT NULL,
"excerpt" TEXT NOT NULL,
"content" TEXT NOT NULL,
"coverImage" TEXT,
"category" TEXT NOT NULL DEFAULT 'News',
"publishedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"order" INTEGER NOT NULL DEFAULT 0,
"galleryJson" TEXT DEFAULT '[]',
"linkedinUrl" TEXT,
"translationsJson" TEXT DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "NewsArticle_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "HeritageSection" (
"id" TEXT NOT NULL,
"type" TEXT NOT NULL DEFAULT 'text',
"title" TEXT,
"content" TEXT,
"mediaUrl" TEXT,
"order" INTEGER NOT NULL DEFAULT 0,
"translationsJson" TEXT DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "HeritageSection_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "SparePart" (
"id" TEXT NOT NULL,
"sku" TEXT NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"mediaJson" TEXT DEFAULT '[]',
"specsJson" TEXT DEFAULT '[]',
"price" DOUBLE PRECISION,
"showPrice" BOOLEAN NOT NULL DEFAULT false,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"translationsJson" TEXT DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "SparePart_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "OperationsSignal" (
"id" TEXT NOT NULL,
"ticketId" TEXT NOT NULL,
"ticketNumber" SERIAL NOT NULL,
"type" TEXT NOT NULL,
"status" TEXT NOT NULL DEFAULT 'PENDING',
"clientName" TEXT NOT NULL,
"clientEmail" TEXT NOT NULL,
"clientCompany" TEXT NOT NULL,
"clientPhone" TEXT,
"message" TEXT,
"cartPayload" TEXT DEFAULT '[]',
"attachedFiles" TEXT DEFAULT '[]',
"aiAnalysis" TEXT,
"emailSentTo" TEXT,
"emailSentAt" TIMESTAMP(3),
"emailError" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "OperationsSignal_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "NotificationRoute" (
"id" TEXT NOT NULL,
"routeType" TEXT NOT NULL,
"emails" TEXT NOT NULL,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "NotificationRoute_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "PageContent" (
"id" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"title" TEXT NOT NULL,
"subtitle" TEXT,
"description" TEXT,
"translationsJson" TEXT DEFAULT '{}',
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "PageContent_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "AdminUser_username_key" ON "AdminUser"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Application_slug_key" ON "Application"("slug");
-- CreateIndex
CREATE UNIQUE INDEX "NewsArticle_slug_key" ON "NewsArticle"("slug");
-- CreateIndex
CREATE UNIQUE INDEX "SparePart_sku_key" ON "SparePart"("sku");
-- CreateIndex
CREATE UNIQUE INDEX "OperationsSignal_ticketId_key" ON "OperationsSignal"("ticketId");
-- CreateIndex
CREATE INDEX "OperationsSignal_type_idx" ON "OperationsSignal"("type");
-- CreateIndex
CREATE INDEX "OperationsSignal_status_idx" ON "OperationsSignal"("status");
-- CreateIndex
CREATE INDEX "OperationsSignal_createdAt_idx" ON "OperationsSignal"("createdAt" DESC);
-- CreateIndex
CREATE UNIQUE INDEX "NotificationRoute_routeType_key" ON "NotificationRoute"("routeType");
-- CreateIndex
CREATE UNIQUE INDEX "PageContent_slug_key" ON "PageContent"("slug");
+270
View File
@@ -0,0 +1,270 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
//url = env("DATABASE_URL")
}
// ------------------------------------------------------
// 1. BÓVEDA DE SEGURIDAD (Usuarios del CMS)
// ------------------------------------------------------
model AdminUser {
id String @id @default(cuid())
username String @unique
email String? // 🔥 NUEVO CAMPO: Correo del administrador
passwordHash String
twoFactorSecret String?
is2FAEnabled Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ------------------------------------------------------
// 2. EL GLOBO HOLOGRÁFICO (Nodos y Casos de Estudio Profundos)
// ------------------------------------------------------
model GlobalNode {
id String @id @default(cuid())
title String // Ej: "Toray Advanced Textiles"
location String
// Ej: "Tokyo, Japan"
lat Float // Ej: 35.6895
lon Float // Ej: 139.6917
// Taxonomía
nodeType String @default("installation") // "installation", "event", "hq"
application String // Ej: "textile-drying", "hq", "event"
stats String // Ej: "2,400 kg/h throughput"
isActive Boolean @default(true) // Permite ocultar un nodo sin borrarlo
// 📖 GEO-CHRONICLE (THE STORY)
projectOverview String? // El Artículo completo / Resumen del evento (Markdown)
energySavings String? // Métrica (Ej: "-45% vs Conventional" o "Stand 4B")
eventDate DateTime?// Fecha para controlar si el evento es pasado o futuro
// 🔥 NUEVOS CAMPOS FASE 1: MULTIMEDIA Y DATASHEET ESPECÍFICO 🔥
mediaFileName String? // Imagen de Portada principal
galleryJson String? @default("[]") // Array de imágenes extra
videosJson String? @default("[]") // Links a videos reales
specificDatasheetJson String? @default("[]") // Ficha técnica de ESTA máquina
model3DPath String? // Ruta al archivo GLB/USDZ
rendersJson String? @default("[]") // Renders 3D fotorrealistas
model3DDimsJson String? // Dimensiones físicas AR: { w, h, d, unit, weight }
// 🌍 MOTOR DE TRADUCCIONES
translationsJson String? @default("{}")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ------------------------------------------------------
// 3. LA BASE DE CONOCIMIENTO (Páginas de Aplicaciones)
// ------------------------------------------------------
model Application {
id String @id @default(cuid())
slug String @unique // Ej: "textile-drying" (Debe coincidir con la URL)
title String
subtitle String
category String
// 🔥 NUEVO: La descripción corta para las tarjetas de la página principal
shortDescription String @default("Learn more about this FLUX RF technology application.")
heroDescription String // Recibirá MARKDOWN para la teoría científica general
// JSONs para estructuras complejas
sectionsJson String
advantagesJson String
datasheetJson String
// Métricas Rápidas para el Dashboard
dashboardMetricsJson String? @default("[]")
isActive Boolean @default(true) // 🔥 NUEVO: Para poder ocultarlas
// 🌍 MOTOR DE TRADUCCIONES
translationsJson String? @default("{}")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ------------------------------------------------------
// 4. NUESTRA HISTORIA (Línea de tiempo de la empresa)
// ------------------------------------------------------
model TimelineEvent {
id String @id @default(cuid())
year String // Ej: "1978" o "1990s"
title String
description String
order Int @default(0) // Para ordenar cronológicamente
isActive Boolean @default(true)
// 🌍 MOTOR DE TRADUCCIONES
translationsJson String? @default("{}")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ------------------------------------------------------
// 5. INSIDE FLUX (Motor de Noticias y Detrás de Cámaras)
// ------------------------------------------------------
model NewsArticle {
id String @id @default(cuid())
slug String @unique
title String
excerpt String // Resumen corto para la tarjeta
content String // El artículo completo (Markdown)
coverImage String? // Ej: "team-meeting.jpg"
category String @default("News")
publishedAt DateTime @default(now())
isActive Boolean @default(true)
// Editor avanzado
order Int @default(0) // Para ordenar las noticias
galleryJson String? @default("[]") // Galería de imágenes extra
linkedinUrl String? // Enlace oficial para LinkedIn
// 🌍 MOTOR DE TRADUCCIONES
translationsJson String? @default("{}")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ------------------------------------------------------
// 6. OUR HERITAGE (La Historia Profunda de Patrizio)
// ------------------------------------------------------
model HeritageSection {
id String @id @default(cuid())
type String @default("text") // "text", "image", "video"
title String?
content String? // Párrafos de la historia
mediaUrl String? // Ej: "patrizio-1980.jpg" o enlace de YouTube
order Int @default(0) // Para ordenar cómo se lee la página
// 🌍 MOTOR DE TRADUCCIONES
translationsJson String? @default("{}")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ------------------------------------------------------
// 7. COMPONENT MATRIX (Catálogo de Repuestos)
// ------------------------------------------------------
model SparePart {
id String @id @default(cuid())
sku String @unique // Identificador único / Referencia (Ej: "FLX-GEN-001")
title String // Nombre de la pieza en Inglés
description String // Descripción técnica / Función (Markdown)
// Multimedia & Ficha Técnica
mediaJson String? @default("[]") // Imágenes, videos, renders 3D
specsJson String? @default("[]") // Array de métricas [{label: "Voltage", value: "24V"}]
// Estrategia de Ventas
price Float? // Precio (Opcional)
showPrice Boolean @default(false) // Interruptor: true = mostrar precio, false = "Request Quote"
isActive Boolean @default(true) // Para ocultar repuestos descontinuados
// 🌍 MOTOR DE TRADUCCIONES (Integración con aiTranslator.ts)
translationsJson String? @default("{}")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ------------------------------------------------------
// 8. OPERATIONS INBOX (Signal Hub - Mesa de Ayuda y Órdenes)
// ------------------------------------------------------
model OperationsSignal {
id String @id @default(cuid())
ticketId String @unique
ticketNumber Int @default(autoincrement()) // Sequential for analytics
type String // "ORDER", "DIAGNOSTIC", "CONSULTATION"
status String @default("PENDING") // "PENDING", "REVIEWING", "RESOLVED"
// Client data
clientName String
clientEmail String
clientCompany String
clientPhone String?
message String?
// Payloads
cartPayload String? @default("[]")
attachedFiles String? @default("[]")
aiAnalysis String?
// Email delivery tracking
emailSentTo String? // Comma-separated list of emails that received notification
emailSentAt DateTime? // When the email was dispatched
emailError String? // Error message if email failed
// 🔥 NUEVO: Relación opcional con el Cliente Registrado (Para el futuro CRM)
clientId String?
client ClientUser? @relation(fields: [clientId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([type])
@@index([status])
@@index([createdAt(sort: Desc)])
}
// ------------------------------------------------------
// 9. RUTAS DE NOTIFICACIÓN (Gestión de Emails)
// ------------------------------------------------------
model NotificationRoute {
id String @id @default(cuid())
routeType String @unique // Ej: "ORDER", "DIAGNOSTIC", "CONSULTATION"
emails String // Correos separados por coma (Ej: "sales@fluxsrl.com, tech@fluxsrl.com")
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ------------------------------------------------------
// 10. PAGE CONTENT (Metadata y Textos de Páginas)
// ------------------------------------------------------
model PageContent {
id String @id @default(cuid())
slug String @unique // Identificador de la página (Ej: "parts-catalog")
title String
subtitle String?
description String?
// 🌍 MOTOR DE TRADUCCIONES
translationsJson String? @default("{}")
updatedAt DateTime @updatedAt
}
// ------------------------------------------------------
// 11. CLIENT PORTAL (Usuarios B2B Aprobados) 🔥 NUEVO
// ------------------------------------------------------
model ClientUser {
id String @id @default(cuid())
email String @unique
passwordHash String
fullName String
companyName String
phone String?
// Control de Acceso
isApproved Boolean @default(false) // Requiere aprobación del Admin
// Historial de Compras/Tickets
signals OperationsSignal[]
lastLoginAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}