Files
FRASA-CAS/api-gateway/prisma/schema.prisma
Consult AS Technology 05c44478ec feat(ai): agente IA interno con RAG sobre NAN + app web en /ai
- API: /api/ai/chat, /conversations, /documents con embeddings qwen3-embedding,
  coseno en SQLite, dedup por hash, historial de conversaciones
- Base de conocimiento semilla (6 docs, 36 chunks): catálogo DIAGONAL,
  propuestas del cotizador, créditos, proceso de venta, FAQ, privacidad
- App agente-ia (Vite/React/Tailwind, StudioBlank) servida en /ai/ vía nginx
- 21 tests nuevos (91/91 verdes)
2026-08-22 03:04:47 +00:00

174 lines
5.0 KiB
Plaintext

// FRASA API Gateway — persistencia local
// Desarrollo: SQLite. Producción: Postgres 16 (cambiar provider y DATABASE_URL).
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite" // prod: "postgresql"
url = env("DATABASE_URL")
}
model Cotizacion {
id String @id @default(uuid())
unidadCodigo String
clienteNombre String
clienteEmail String?
clienteTelefono String?
tipoPropuesta String // BANCARIO | INFONAVIT | CONTADO | SEMI_CONTADO
acabados Boolean
apartado Float // TODO prod: Decimal en Postgres
descuento Float // fracción (0.02 = 2%)
precioLista Float // TODO prod: Decimal en Postgres
precioFinal Float
enganche Float
numMensualidades Int
mensualidad Float? // null => N/A (Contado)
pagoFinal Float
mondayItemId String?
createdAt DateTime @default(now())
@@index([unidadCodigo])
}
model Cliente {
id String @id @default(uuid())
nombreCompleto String
curp String
rfc String
email String?
celular String?
proyecto String
unidadCodigo String?
// Payload completo del alta como JSON serializado (SQLite no tiene Json nativo;
// en Postgres puede migrarse a la columna Json sin cambiar el contrato).
payloadJson String
firmaPng String? // base64 opcional
mondayContactoId String?
mondayApartadoId String?
createdAt DateTime @default(now())
documentos Documento[]
@@index([curp])
}
model Documento {
id String @id @default(uuid())
clienteId String
cliente Cliente @relation(fields: [clienteId], references: [id], onDelete: Cascade)
tipo String // INE | CONSTANCIA_RFC | CURP | COMPROBANTE_DOMICILIO | ACTA_NACIMIENTO | OTRO
nombreArchivo String
ruta String
mime String
tamano Int
createdAt DateTime @default(now())
@@index([clienteId])
}
model PlanPago {
id String @id @default(uuid())
ventaRef String?
clienteNombre String
clienteTelefono String?
unidadCodigo String
proyecto String
fechaInicio DateTime // se normaliza a medianoche local
engancheTotal Float // TODO prod: Decimal en Postgres
numPagos Int
mensualidad Float
tasaMoraMensual Float @default(0)
status String @default("ACTIVO") // ACTIVO | CANCELADO (LIQUIDADO se deriva)
createdAt DateTime @default(now())
notas NotaPlan[]
pagos Pago[]
@@index([unidadCodigo])
}
model Pago {
id String @id @default(uuid())
planId String
plan PlanPago @relation(fields: [planId], references: [id], onDelete: Cascade)
numPago Int
fechaVencimiento DateTime
monto Float
montoPagado Float @default(0)
aplicaciones AplicacionPago[]
@@index([planId])
@@index([fechaVencimiento])
}
model AplicacionPago {
id String @id @default(uuid())
pagoId String
pago Pago @relation(fields: [pagoId], references: [id], onDelete: Cascade)
fechaPago DateTime
monto Float
referencia String
@@index([pagoId])
}
// Estado persistente de las automatizaciones de Monday (round-robin, recordatorios).
// Clave-valor genérico: 'rr:indice', 'rr:vendedores', 'recordatorio:<itemId>:<fecha>', etc.
model AutomatizacionState {
clave String @id
valor String
updatedAt DateTime @updatedAt
}
model NotaPlan {
id String @id @default(uuid())
planId String
plan PlanPago @relation(fields: [planId], references: [id], onDelete: Cascade)
fecha DateTime @default(now())
texto String
@@index([planId])
}
// ---------- Agente IA interno (RAG) ----------
// Documento de la base de conocimiento; `hash` (sha256 del contenido) permite
// re-indexar solo cuando cambió.
model AIDocumento {
id String @id @default(uuid())
titulo String @unique
contenido String
hash String
createdAt DateTime @default(now())
chunks AIChunk[]
}
model AIChunk {
id String @id @default(uuid())
documentoId String
documento AIDocumento @relation(fields: [documentoId], references: [id], onDelete: Cascade)
texto String
embedding String // JSON array de floats (SQLite no tiene vector nativo)
orden Int
@@index([documentoId])
}
model AIConversacion {
id String @id @default(uuid())
createdAt DateTime @default(now())
mensajes AIMensaje[]
}
model AIMensaje {
id String @id @default(uuid())
conversacionId String
conversacion AIConversacion @relation(fields: [conversacionId], references: [id], onDelete: Cascade)
rol String // user | assistant
contenido String
fuentes String? // JSON [{titulo, score}] solo en mensajes del asistente
createdAt DateTime @default(now())
@@index([conversacionId])
}