653 lines
14 KiB
Markdown
653 lines
14 KiB
Markdown
# 🗄️ 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)
|
|
```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
|
|
```prisma
|
|
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)
|
|
```prisma
|
|
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
|
|
```prisma
|
|
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
|
|
```prisma
|
|
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
|
|
```prisma
|
|
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
|
|
```prisma
|
|
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
|
|
```prisma
|
|
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
|
|
```prisma
|
|
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)
|
|
```prisma
|
|
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
|
|
```prisma
|
|
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:
|
|
1. **Nombre de la aplicación**
|
|
2. **Logo (texto)** - Imagen para el header
|
|
3. **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
|
|
```bash
|
|
cd /Users/cesarmendivil/WebstormProjects/Nexus
|
|
npx prisma migrate dev
|
|
```
|
|
|
|
### 3. Generar Cliente
|
|
```bash
|
|
npx prisma generate
|
|
```
|
|
|
|
### 4. Usar Prisma en Backend
|
|
```typescript
|
|
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
|
|
```typescript
|
|
POST /api/auth/register
|
|
POST /api/auth/login
|
|
POST /api/auth/logout
|
|
GET /api/auth/me
|
|
```
|
|
|
|
#### 2. AI Providers
|
|
```typescript
|
|
GET /api/providers
|
|
POST /api/providers
|
|
PUT /api/providers/:id
|
|
DELETE /api/providers/:id
|
|
```
|
|
|
|
#### 3. Conversations
|
|
```typescript
|
|
GET /api/conversations
|
|
POST /api/conversations
|
|
GET /api/conversations/:id
|
|
DELETE /api/conversations/:id
|
|
POST /api/conversations/:id/messages
|
|
```
|
|
|
|
#### 4. Knowledge Base
|
|
```typescript
|
|
GET /api/knowledge
|
|
POST /api/knowledge
|
|
POST /api/knowledge/:id/documents
|
|
GET /api/knowledge/:id/documents
|
|
DELETE /api/documents/:id
|
|
```
|
|
|
|
#### 5. Agents
|
|
```typescript
|
|
GET /api/agents
|
|
POST /api/agents
|
|
PUT /api/agents/:id
|
|
DELETE /api/agents/:id
|
|
```
|
|
|
|
#### 6. Settings
|
|
```typescript
|
|
GET /api/settings
|
|
PUT /api/settings
|
|
POST /api/settings/branding/upload
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Integración con Frontend
|
|
|
|
### useChat Hook (Actualizar)
|
|
```typescript
|
|
// 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)
|
|
```typescript
|
|
// En lugar de localStorage
|
|
const providers = await fetch('/api/providers');
|
|
|
|
// Guardar provider
|
|
await fetch('/api/providers', {
|
|
method: 'POST',
|
|
body: JSON.stringify(providerData),
|
|
});
|
|
```
|
|
|
|
### SettingsBranding (Actualizar)
|
|
```typescript
|
|
// 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
|
|
```bash
|
|
npx prisma studio
|
|
```
|
|
Abre interfaz web en `http://localhost:5555`
|
|
|
|
### Crear Migración
|
|
```bash
|
|
npx prisma migrate dev --name migration_name
|
|
```
|
|
|
|
### Reset Database
|
|
```bash
|
|
npx prisma migrate reset
|
|
```
|
|
|
|
### Pull Schema from DB
|
|
```bash
|
|
npx prisma db pull
|
|
```
|
|
|
|
### Push Schema to DB (sin migración)
|
|
```bash
|
|
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**
|
|
|