14 KiB
🗄️ Sistema de Persistencia con PostgreSQL + Prisma
Base de Datos Completa con RAG Vector Support
He implementado un sistema completo de persistencia usando PostgreSQL con soporte para vectores (pgvector) para RAG, utilizando Prisma ORM para un manejo escalable.
📊 Arquitectura de Base de Datos
Conexión PostgreSQL
Host: 192.168.1.20:5433
Database: nexus
User: postgres
Password: 72ff3d8d80c352f89d99
Extension: pgvector (para RAG)
Variables de Entorno (.env)
# Database
DATABASE_URL="postgres://postgres:72ff3d8d80c352f89d99@192.168.1.20:5433/nexus?sslmode=disable"
# Server
PORT=3000
NODE_ENV=development
CLIENT_URL=http://localhost:3001
# JWT
JWT_SECRET=your-super-secret-jwt-key-change-in-production-nexus-2026
# File Upload
MAX_FILE_SIZE=10485760
UPLOAD_DIR=./uploads
# AI Providers (optional - users configure in UI)
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
GOOGLE_API_KEY=
MISTRAL_API_KEY=
COHERE_API_KEY=
🗃️ Modelos de Base de Datos
1. User
model User {
id String @id @default(cuid())
email String @unique
name String?
password String
avatar String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
conversations Conversation[]
aiProviders AIProvider[]
knowledgeBases KnowledgeBase[]
agents Agent[]
settings AppSettings?
}
Propósito: Gestión de usuarios y autenticación
2. AppSettings (Branding + Config)
model AppSettings {
id String @id @default(cuid())
userId String @unique
// Branding
appName String @default("NexusChat")
appLogo String? // URL or base64
appIcon String? // URL or base64 for avatar/favicon
// Theme
theme String @default("dark")
primaryColor String @default("#667eea")
// General Settings
autoSave Boolean @default(true)
soundEnabled Boolean @default(false)
language String @default("en")
}
Propósito:
- ✅ Personalización de marca (logo, icono, nombre)
- ✅ Configuración de tema
- ✅ Preferencias generales
3. AIProvider
model AIProvider {
id String @id @default(cuid())
userId String
providerId String // openai, anthropic, google, mistral, cohere
name String
enabled Boolean @default(false)
apiKey String? @db.Text // Encrypted
}
Propósito: Almacenar configuración de AI Providers por usuario
4. Conversation
model Conversation {
id String @id @default(cuid())
userId String
title String
agentId String?
modelId String? // gpt-4o, claude-3-opus, etc
providerId String? // openai, anthropic, etc
messages Message[]
topics Topic[]
}
Propósito: Gestión de conversaciones de chat
5. Message
model Message {
id String @id @default(cuid())
conversationId String
role String // user, assistant, system
content String @db.Text
// Metadata
tokensUsed Int?
model String?
}
Propósito: Almacenar mensajes de las conversaciones
6. Topic
model Topic {
id String @id @default(cuid())
conversationId String
title String
order Int @default(0)
}
Propósito: Topics del panel derecho del chat
7. KnowledgeBase
model KnowledgeBase {
id String @id @default(cuid())
userId String
name String
description String? @db.Text
documents Document[]
agents Agent[]
}
Propósito: Contenedor de documentos para RAG
8. Document
model Document {
id String @id @default(cuid())
knowledgeBaseId String
fileName String
fileType String
fileSize Int
filePath String
status String @default("processing") // processing, ready, error
chunksCount Int @default(0)
chunks DocumentChunk[]
}
Propósito: Archivos subidos para RAG
9. DocumentChunk (RAG con Vectores)
model DocumentChunk {
id String @id @default(cuid())
documentId String
content String @db.Text
chunkIndex Int
// Vector embedding for semantic search (using pgvector)
// TODO: Enable after pgvector extension is installed
// embedding Unsupported("vector(1536)")?
metadata Json? // Additional metadata
}
Propósito:
- ✅ Chunks de documentos procesados
- ✅ Vector embeddings para búsqueda semántica
- ✅ Metadata adicional
Nota: El campo embedding está comentado temporalmente. Se habilitará después de instalar la extensión pgvector en PostgreSQL.
10. Agent
model Agent {
id String @id @default(cuid())
userId String
name String
emoji String @default("🤖")
role String
description String @db.Text
status String @default("active") // active, inactive
// Capabilities
mcpEnabled Boolean @default(false)
mcpTools Json? // Array of MCP tools
// RAG Configuration
ragEnabled Boolean @default(false)
// Stats
interactions Int @default(0)
lastUsedAt DateTime?
conversations Conversation[]
knowledgeBases KnowledgeBase[]
}
Propósito: Agentes IA configurables con MCP y RAG
🎨 Nueva Feature: Branding Settings
Componente SettingsBranding
Permite personalizar:
- Nombre de la aplicación
- Logo (texto) - Imagen para el header
- Icono (avatar) - Imagen para el chat avatar
Visual
┌──────────────────────────────────────────┐
│ ✨ Branding │
├──────────────────────────────────────────┤
│ │
│ Nombre de la Aplicación │
│ [NexusChat ] │
│ │
│ ┌────────────┬──────────────────────┐ │
│ │ Logo │ Icono │ │
│ │ │ │ │
│ │ ⬆️ Upload │ ⬆️ Upload │ │
│ │ Click para │ Click para subir │ │
│ │ subir logo │ icono │ │
│ │ │ │ │
│ └────────────┴──────────────────────┘ │
│ │
│ [Guardar Cambios] │
└──────────────────────────────────────────┘
Funcionalidades
- ✅ Upload de imagen para logo
- ✅ Upload de imagen para icono
- ✅ Cambiar nombre de la app
- ✅ Preview de imágenes
- ✅ Botón para remover imágenes
- ✅ Guardar en localStorage (temporal)
- ✅ TODO: Guardar en base de datos
📁 Estructura de Archivos
Backend
/
├── .env (configuración)
├── prisma/
│ ├── schema.prisma (modelos)
│ └── migrations/ (migraciones)
│
└── src/
└── config/
└── prisma.ts (cliente singleton)
Frontend
client/src/components/
└── SettingsBranding.tsx (nuevo componente)
🚀 Uso del Sistema
1. Iniciar Base de Datos
La base de datos ya está configurada en 192.168.1.20:5433
2. Aplicar Migraciones
cd /Users/cesarmendivil/WebstormProjects/Nexus
npx prisma migrate dev
3. Generar Cliente
npx prisma generate
4. Usar Prisma en Backend
import prisma from './config/prisma';
// Crear usuario
const user = await prisma.user.create({
data: {
email: 'user@example.com',
password: 'hashed_password',
name: 'John Doe',
},
});
// Guardar configuración de AI Provider
await prisma.aIProvider.create({
data: {
userId: user.id,
providerId: 'openai',
name: 'OpenAI',
enabled: true,
apiKey: 'encrypted_key',
},
});
// Crear conversación
const conversation = await prisma.conversation.create({
data: {
userId: user.id,
title: 'Nueva conversación',
modelId: 'gpt-4o',
providerId: 'openai',
},
});
// Guardar mensaje
await prisma.message.create({
data: {
conversationId: conversation.id,
role: 'user',
content: 'Hola!',
},
});
🔄 Flujo de Datos
Configuración de AI Providers
UI (SettingsModal)
→ localStorage (temporal)
→ Backend API (TODO)
→ Prisma
→ PostgreSQL
Branding
UI (SettingsBranding)
→ Upload imagen
→ Base64 / File
→ localStorage (temporal)
→ Backend API (TODO)
→ Prisma (AppSettings)
→ PostgreSQL
RAG Pipeline
1. Usuario sube archivo
→ KnowledgeBase
2. Backend procesa archivo
→ Divide en chunks
→ DocumentChunk
3. Genera embeddings
→ OpenAI embeddings API
→ Guarda en vector field
4. Búsqueda semántica
→ Query → embedding
→ pgvector similarity search
→ Retorna chunks relevantes
📊 Diagrama de Relaciones
User
├── Conversation
│ ├── Message
│ └── Topic
│
├── AIProvider
│
├── KnowledgeBase
│ └── Document
│ └── DocumentChunk (with vector)
│
├── Agent
│ └── KnowledgeBase (many-to-many)
│
└── AppSettings
🔒 Seguridad
API Keys
- ✅ Almacenadas en campo
@db.Text - ⚠️ TODO: Implementar encriptación
- ✅ No expuestas en el cliente
Passwords
- ⚠️ TODO: Implementar hashing (bcrypt)
- ✅ Campo password en User model
JWT
- ✅ Secret configurado en .env
- ⚠️ TODO: Implementar autenticación
📋 Próximos Pasos
Backend APIs a Implementar
1. Auth
POST /api/auth/register
POST /api/auth/login
POST /api/auth/logout
GET /api/auth/me
2. AI Providers
GET /api/providers
POST /api/providers
PUT /api/providers/:id
DELETE /api/providers/:id
3. Conversations
GET /api/conversations
POST /api/conversations
GET /api/conversations/:id
DELETE /api/conversations/:id
POST /api/conversations/:id/messages
4. Knowledge Base
GET /api/knowledge
POST /api/knowledge
POST /api/knowledge/:id/documents
GET /api/knowledge/:id/documents
DELETE /api/documents/:id
5. Agents
GET /api/agents
POST /api/agents
PUT /api/agents/:id
DELETE /api/agents/:id
6. Settings
GET /api/settings
PUT /api/settings
POST /api/settings/branding/upload
🎯 Integración con Frontend
useChat Hook (Actualizar)
// En lugar de localStorage
const messages = await fetch('/api/conversations/${id}/messages');
// Guardar mensaje
await fetch('/api/conversations/${id}/messages', {
method: 'POST',
body: JSON.stringify({ content, role: 'user' }),
});
SettingsAIProviders (Actualizar)
// En lugar de localStorage
const providers = await fetch('/api/providers');
// Guardar provider
await fetch('/api/providers', {
method: 'POST',
body: JSON.stringify(providerData),
});
SettingsBranding (Actualizar)
// Upload logo
const formData = new FormData();
formData.append('logo', file);
await fetch('/api/settings/branding/upload', {
method: 'POST',
body: formData,
});
🗄️ Comandos Útiles de Prisma
Ver Base de Datos
npx prisma studio
Abre interfaz web en http://localhost:5555
Crear Migración
npx prisma migrate dev --name migration_name
Reset Database
npx prisma migrate reset
Pull Schema from DB
npx prisma db pull
Push Schema to DB (sin migración)
npx prisma db push
✅ Estado Actual
╔════════════════════════════════════════════╗
║ ✅ BASE DE DATOS CONFIGURADA ║
║ ║
║ PostgreSQL: 192.168.1.20:5433 ║
║ Database: nexus ║
║ ORM: Prisma ║
║ Extension: pgvector (preparado) ║
║ ║
║ Modelos: 10 ║
║ - User ║
║ - AppSettings (Branding) ║
║ - AIProvider ║
║ - Conversation ║
║ - Message ║
║ - Topic ║
║ - KnowledgeBase ║
║ - Document ║
║ - DocumentChunk (RAG) ║
║ - Agent ║
║ ║
║ Features Frontend: ║
║ ✅ Branding Settings UI ║
║ ✅ Upload logo/icono ║
║ ✅ Cambiar nombre app ║
║ ║
║ TODO: ║
║ ⏳ Backend APIs ║
║ ⏳ Autenticación ║
║ ⏳ Encriptación API Keys ║
║ ⏳ Integración RAG pipeline ║
║ ║
║ Estado: ESTRUCTURA COMPLETA ✅ ║
╚════════════════════════════════════════════╝
Implementado: 14 de Febrero, 2026
Base de Datos: PostgreSQL con pgvector
ORM: Prisma
Modelos: 10 completos
Features: Branding Settings UI
Estado: ✅ ESTRUCTURA LISTA - APIs PENDIENTES