Skip to Content
📚 Bienvenido a la documentación técnica de Rial AI 👋
🗄️ Base de Datos🗂️ Esquema de Base de Datos

🗂️ Esquema de Base de Datos

La base de datos de Rial AI está modelada de manera relacional en PostgreSQL y representa las relaciones entre compañías, marcas, usuarios, prendas, proyectos de generación, imágenes, modelos virtuales, publicaciones y control de créditos.

📊 Estructura General

Todos los modelos en nuestra base de datos siguen un patrón consistente que incluye:

  • id: Identificador incremental para uso interno del desarrollador
  • publicId: UUID (identificador único) que se puede compartir con el usuario y frontend de forma segura
  • createdAt: Timestamp de creación del registro
  • updatedAt: Timestamp de última actualización

¿Por qué dos IDs? El id interno es secuencial y optimizado para consultas de base de datos, mientras que el publicId es un UUID que no revela información sobre la cantidad de registros y es seguro para exponer públicamente.


🏢 Modelos de Organización

Company (Compañía)

Representa a una empresa que puede tener múltiples marcas.

model Company { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt name String @unique logo String credits Int @default(0) // deprecado brands Brand[] users User[] folders ProjectFolder[] models Model[] }

Campos Clave

  • name: Nombre único de la compañía
  • logo: URL del logo corporativo
  • credits: Saldo actual de créditos (default: 0)
    • Nota: Por ahora no manejamos activamente el sistema de créditos

Relaciones

  • brands[]: Una compañía puede tener múltiples marcas
  • users[]: Una compañía puede tener múltiples usuarios
  • folders[]: Carpetas de proyectos de la compañía
  • models[]: Modelos virtuales asociados a la compañía

Brand (Marca)

Cada marca pertenece a una compañía y contiene sus propias prendas, proyectos, usuarios y modelos virtuales. El par (name, companyId) es único.

model Brand { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt name String logo String companyId Int company Company @relation(fields: [companyId], references: [id]) garments Garment[] projects Project[] users User[] // N:M con User models Model[] // N:M con Model settings BrandSettings @relation(fields: [settingsId], references: [id]) settingsId Int @unique } // Índice único: (name, companyId) model BrandSettings { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) brand Brand? outputPoses PoseSetting[] @relation("OutputPoses") inputPoses PoseSetting[] @relation("InputPoses") imageValidations Json? aliases String[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model PoseSetting { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) pose Pose? garmentView GarmentView? suffix String? suffixRule SuffixRule? projectType ProjectType inputBrandSettingsId Int? outputBrandSettingsId Int? inputBrandSettings BrandSettings? @relation("InputPoses", fields: [inputBrandSettingsId], references: [id]) outputBrandSettings BrandSettings? @relation("OutputPoses", fields: [outputBrandSettingsId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } enum SuffixRule { HIGHEST // Toma el sufijo más alto disponible LOWEST // Toma el sufijo más bajo disponible }

Campos Clave

  • name: Nombre de la marca (único por compañía)
  • logo: URL del logo de la marca
  • companyId: Referencia a la compañía propietaria
  • settingsId: Configuración de poses e inputs de la marca (1:1)

BrandSettings — Configuración de la marca

CampoTipoDescripción
outputPosesPoseSetting[]Poses de salida configuradas para esta marca
inputPosesPoseSetting[]Poses de entrada (imágenes de prenda) configuradas
imageValidationsJson?Reglas de validación de imágenes de entrada
aliasesString[]Alias de nombre de marca para mapeo externo

PoseSetting — Configuración de pose por tipo de proyecto

Define cómo se mapean poses de entrada y salida para un tipo de proyecto específico.

CampoTipoDescripción
posePose?Pose objetivo
garmentViewGarmentView?Vista de prenda asociada
suffixString?Sufijo de nombre de archivo
suffixRuleSuffixRule?Regla para elegir sufijo (HIGHEST/LOWEST)
projectTypeProjectTypeTipo de proyecto al que aplica

Ejemplo de BrandSettings

Supongamos una marca que:

  • El cliente sube imágenes de prenda con sufijos _front, _back y _zoom en el nombre del archivo
  • Se quieren generar poses AMERICAN_FRONT y FULLBODY_FRONT para proyectos BATCH, y AMERICAN_FRONT para PRODUCT
  • Se acepta que si no encuentra sufijo exacto, el sistema asigne la vista FRONT usando el criterio HIGHEST
  • Las imágenes deben ser JPG o PNG, y tener al menos 800×800 px
{ "aliases": ["lacroix", "c. lacroix"], "imageValidations": { "minWidth": 800, "minHeight": 800, "allowedExtensions": ["jpg", "jpeg", "png"] }, "inputPoses": [ { "garmentView": "BACK", "suffix": "_back", "projectType": "BATCH" }, { "garmentView": "ZOOM", "suffix": "_zoom", "projectType": "BATCH" } ], "outputPoses": [ { "pose": "AMERICAN_FRONT", "suffix": "001", "projectType": "BATCH" }, { "pose": "FULLBODY_FRONT", "suffix": "002", "projectType": "BATCH" }, { "pose": "AMERICAN_FRONT", "suffix": "001", "projectType": "PRODUCT" } ] }

Cómo se usa en la práctica:

  • aliases — cuando el sistema recibe un Excel con el nombre "c. lacroix", lo resuelve a la marca correcta aunque no coincida exactamente con name.
  • inputPoses — al subir el archivo camiseta_front.jpg, el sistema identifica que es vista FRONT porque termina en _front.
  • outputPoses — para un proyecto BATCH, el worker genera dos imágenes por SKU (AMERICAN_FRONT nombrada …_001.jpg y FULLBODY_FRONT nombrada …_002.jpg).
  • imageValidations — al procesar el Excel de entrada, se rechaza cualquier imagen menor a 800×800 px o que no sea JPG/PNG.

Relaciones

  • company: Pertenece a una compañía
  • users[]: Usuarios asignados a la marca
  • garments[]: Prendas de la marca
  • projects[]: Proyectos de generación
  • models[]: Modelos virtuales personalizados
  • settings: Configuración de poses e inputs (1:1 con BrandSettings)

User (Usuario)

Representa a un miembro de la plataforma con diferentes niveles de acceso, permisos granulares y asociación a marcas mediante relación N:M.

model User { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt nickname String @default("") email String @unique phoneNumber String? notificationsEnabled NotificationTemplateType[] role UserRole @default(COMPANY_ADMIN) companyId Int? sessionId String @unique transactions CreditTransaction[] company Company? @relation(fields: [companyId], references: [id]) approvals GeneratedImage[] apiKey ApiKey? brands Brand[] permissions RolePermission[] allowedModelSexes Gender[] job Job[] @relation("UserJob") chatMessages ChatMessage[] } enum UserRole { ADMIN COMPANY_ADMIN BRAND_ADMIN } enum RolePermission { // Permisos del usuario PROJECT_CREATOR // Puede crear proyectos REVIEWER // Puede revisar imágenes DOWNLOADER // Puede descargar imágenes PERMISSION_ADMIN // Puede manejar permisos de otros usuarios VIEWER // Puede ver el detalle de las imágenes }

Campos Clave

  • email: Email único del usuario (usado para autenticación)
  • nickname: Nombre para mostrar (Actualmente usado cuando se envían notificaciones)
  • phoneNumber: Teléfono (opcional, usado para el envío de notificaciones)
  • notificationsEnabled: Tipos de notificación que el usuario tiene habilitados
  • role: Nivel de acceso del usuario
    • ADMIN: Acceso completo a toda la plataforma
    • COMPANY_ADMIN: Administrador de una compañía específica
    • BRAND_ADMIN: Administrador de marcas en específico
  • permissions: Permisos granulares
  • allowedModelSexes: Géneros de modelo permitidos para este usuario
  • sessionId: Identificador único de sesión (relacionado con autenticación Supabase)
  • companyId: Referencia a compañía (para usuarios de tipo COMPANY_ADMIN y BRAND_ADMIN)

Relaciones

  • company: Compañía asociada (para usuarios de tipo BRAND_ADMIN o COMPANY_ADMIN)
  • brands[]: Marcas a las que tiene acceso (para usuarios de tipo BRAND_ADMIN)
  • apiKey: API key asociada si existe (opcional)
  • approvals[]: Imágenes generadas que revisó este usuario
  • job[]: Jobs asíncronos creados por el usuario
  • chatMessages[]: Mensajes de chat enviados por el usuario

ApiKey (Clave de API)

Almacena claves de API para autenticación de integraciones. Cada usuario puede tener como máximo una API key.

model ApiKey { id Int @id @default(autoincrement()) publicId String @unique name String prefix String @unique // Primeros caracteres visibles para identificación hash String // Hash de la clave (nunca se almacena en claro) ownerId Int @unique owner User @relation(fields: [ownerId], references: [id]) isDisabled Boolean @default(false) lastUsedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }

Campos Clave

  • name: Nombre descriptivo de la clave (ej. “Integración Excel”)
  • prefix: Prefijo visible de la clave para que el usuario identifique cuál es
  • hash: Hash de la clave secreta (no se almacena el valor en claro)
  • ownerId: Usuario propietario (relación 1:1)
  • isDisabled: Si está deshabilitada no se puede usar para autenticación
  • lastUsedAt: Última vez que se usó la clave (auditoría)

Relaciones

  • owner: Usuario propietario de la API key

👕 Gestión de Prendas

Garment (Prenda)

Representa las prendas subidas por las marcas para ser utilizadas en los proyectos de generación.

model Garment { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt season String? type GarmentType brandId Int? brand Brand? @relation(fields: [brandId], references: [id]) images GarmentImage[] projects ProjectImage[] // N:M: prendas usadas en una entrada de proyecto result GeneratedImage[] // N:M: imágenes generadas que incluyen esta prenda } enum GarmentType { FOOTWEAR // Zapatos, botas, sandalias UPPER_TRUNK // Camisetas, blusas, chaquetas LOWER_TRUNK // Pantalones, faldas, shorts FULL_BODY // Conjuntos completos FACESWAP // Imágenes para proyectos de tipo faceswap BYPASS // Imagen en proyecto FACESWAP que no necesita generación PRODUCT // Imágenes de producto para proyectos PRODUCT }

Campos Clave

  • name: Nombre descriptivo de la prenda
  • type: Categoría de la prenda
    • FOOTWEAR: Zapatos, botas, sandalias, etc.
    • UPPER_TRUNK: Camisetas, blusas, chaquetas, etc.
    • LOWER_TRUNK: Pantalones, faldas, shorts, etc.
    • FULL_BODY: Conjuntos completos
    • FACESWAP: Imágenes para proyectos de tipo faceswap
    • BYPASS: Prenda que se pasa directamente sin procesamiento
    • PRODUCT: Imágenes de producto para proyectos PRODUCT
  • season: Temporada asociada (opcional) - ej: “Verano 2024”, “Otoño/Invierno 2024”
  • brandId: Referencia opcional a la marca propietaria

Relaciones

  • brand: Marca propietaria de la prenda (opcional)
  • images[]: Imágenes asociadas a la prenda
  • projects[]: Entradas de proyecto (ProjectImage) donde se utiliza la prenda (N:M)
  • result[]: Imágenes generadas que incluyen esta prenda (N:M)

GarmentImage (Imagen de Prenda)

Almacena las imágenes originales de las prendas subidas por las marcas.

model GarmentImage { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt name String url String garmentId Int garment Garment @relation(fields: [garmentId], references: [id]) viewType GarmentView? } enum GarmentView { FRONT BACK ZOOM OTHER }

Campos Clave

  • name: Nombre del archivo de imagen
  • url: URL de la imagen almacenada en Google Cloud Storage
  • viewType: Vista de la prenda que muestra la imagen (FRONT, BACK, ZOOM, OTHER)
  • garmentId: Referencia a la prenda asociada

Relaciones

  • garment: Prenda a la que pertenece la imagen

🎯 Sistema de Proyectos

ProjectFolder (Carpeta de Proyectos)

Agrupa proyectos bajo un nombre, tipo, temporada y descripción. La compañía organiza su trabajo en carpetas; cada carpeta tiene estados visibles para admin y para cliente.

model ProjectFolder { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt name String projectType ProjectType season String? description String? adminStatus AdminStatus @default(CREATING) clientStatus ClientStatus @default(CREATING) companyId Int company Company @relation(fields: [companyId], references: [id]) projects Project[] notifications Notification[] } // Índice único: (companyId, name) enum ProjectType { BATCH FACESWAP PRODUCT } enum AdminStatus { CREATING IN_PROGRESS WAITING_APPROVAL REJECTED COMPLETED CANCELLED UNPUBLISHED } enum ClientStatus { CREATING IN_PROGRESS PENDING_APPROVAL IN_REVIEW PENDING_DOWNLOAD COMPLETED CANCELLED }

Campos Clave

  • name: Nombre de la carpeta (único por compañía)
  • projectType: Tipo de caso/proyecto
    • BATCH: Generación masiva de prendas individuales
    • FACESWAP: Reemplazo de rostros
    • PRODUCT: Generación de imágenes de producto
  • season: Temporada asociada (opcional)
  • description: Descripción de la carpeta
  • adminStatus: Estado visible para administradores (flujo interno)
  • clientStatus: Estado visible para el cliente (flujo de aprobación/descarga)

Relaciones

  • company: Compañía propietaria de la carpeta
  • projects[]: Proyectos contenidos en la carpeta
  • notifications[]: Notificaciones asociadas a esta carpeta

Project (Proyecto)

Un proyecto define una generación concreta dentro de una carpeta: opciones en JSON, marca y carpeta. No tiene nombre propio; el nombre, temporada y descripción están en la carpeta.

model Project { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt adminStatus AdminStatus @default(CREATING) clientStatus ClientStatus @default(CREATING) statusRank Int @default(99) // Deprecado statusRankAdmin Int @default(99) // Deprecado brandId Int options Json folderId Int brand Brand @relation(fields: [brandId], references: [id]) folder ProjectFolder @relation(fields: [folderId], references: [id]) images GeneratedImage[] uploads ProjectImage[] models Model[] chats Chat[] } // Índice único: (options, brandId, folderId)

Campos Clave

  • adminStatus / clientStatus: Estados del proyecto (mismos enums que ProjectFolder)
  • options: Configuración en JSON con parámetros específicos del tipo de proyecto
  • brandId: Marca propietaria del proyecto
  • folderId: Carpeta a la que pertenece el proyecto

Relaciones

  • brand: Marca propietaria del proyecto
  • folder: Carpeta que agrupa este proyecto
  • uploads[]: Imágenes de entrada (ProjectImage)
  • images[]: Imágenes generadas en el proyecto
  • models[]: Modelos virtuales asignados al proyecto (N:M)
  • chats[]: Hilos de chat asociados al proyecto

Tipos de optionsProjectOptions

El campo options es un JSON tipado en src/types/projectOptions.ts. Su forma varía según el tipo de proyecto:

type ProjectOptions = | FaceswapProjectOptions | BatchProjectOptions | ProductProjectOptions;
CommonProjectOptions — base compartida para FACESWAP y BATCH
CampoTipoRequeridoDescripción
genderProjectGenderNoGénero del modelo
agenumberNoEdad del modelo
enum ProjectGender { MALE // Hombre FEMALE // Mujer UNISEX // Unisex OTHER // Otro }
FaceswapProjectOptions — proyectos FACESWAP

Extiende CommonProjectOptions sin campos adicionales.

CampoTipoRequeridoDescripción
genderProjectGenderNoGénero del modelo
agenumberNoEdad del modelo
BatchProjectOptions — proyectos BATCH

Extiende CommonProjectOptions con poses y tipo de medio.

CampoTipoRequeridoDescripción
genderProjectGenderNoGénero del modelo
agenumberNoEdad del modelo
posesPose[]Lista de poses a generar
mediaTypeMediaTypeTipo de medio de salida
ProductProjectOptions — proyectos de producto
CampoTipoRequeridoDescripción
posesPose[]Lista de poses a generar
mediaTypeMediaTypeNoTipo de medio de salida
Enums auxiliares
enum Pose { AMERICAN_FRONT // Plano americano, frente AMERICAN_BACK // Plano americano, espalda AMERICAN_SIDE // Plano americano, lateral FULLBODY_FRONT // Cuerpo completo, frente FULLBODY_BACK // Cuerpo completo, espalda FULLBODY_SIDE // Cuerpo completo, lateral ZOOM // Zoom / detalle } enum MediaType { IMAGE // Imagen estática VIDEO // Video }

ProjectImage (SKU)

Representa una entrada de generación dentro de un proyecto, es decir, un SKU. Tiene estados separados para vista admin y cliente.

model ProjectImage { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt settings Json projectId Int project Project @relation(fields: [projectId], references: [id]) images GeneratedImage[] garments Garment[] // N:M: prendas usadas en esta entrada SKU String adminStatus AdminStatus @default(IN_PROGRESS) clientStatus ClientStatus @default(IN_PROGRESS) chats Chat[] }

Campos Clave

  • settings: Configuración específica en JSON — su forma varía según el tipo de proyecto (ver abajo)
  • SKU: Código de identificación del producto
  • adminStatus: Estado para administradores (mismo enum AdminStatus)
  • clientStatus: Estado para el cliente (mismo enum ClientStatus)
  • projectId: Referencia al proyecto

Tipos de settingsProjectImageSettings

El campo settings está tipado en src/types/projectImageSettings.ts:

type ProjectImageSettings = | BatchProjectImageSettings | ProductProjectImageSettings;
BatchProjectImageSettings — proyectos BATCH
CampoTipoRequeridoDescripción
fitstringNoFit de la prenda (ej. baggy)
commentstringNoComentario o instrucción libre para el generador
backgroundColorstringNoColor de fondo (ej. "#FFFFFF")
ProductProjectImageSettings — proyectos PRODUCT
CampoTipoRequeridoDescripción
descriptionstringNoDescripción del producto para el generador
materialstringNoMaterial de la prenda (ej. "100% algodón")
dimensionsstringNoDimensiones del producto (ej. "30x40cm")

Relaciones

  • project: Proyecto al que pertenece
  • garments[]: Prendas utilizadas en esta generación (N:M)
  • images[]: Imágenes generadas para esta entrada
  • chats[]: Hilos de chat asociados a este SKU

🖼️ Gestión de Imágenes

GeneratedImage (Imagen Generada)

Almacena las imágenes generadas por IA con sistema de versionado, aprobación y relación N:M con prendas.

model GeneratedImage { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) name String url String? status ImageStatus @default(PENDING) reason String? uploadId Int projectId Int project Project @relation(fields: [projectId], references: [id]) upload ProjectImage @relation(fields: [uploadId], references: [id]) previous GeneratedImage? @relation("PreviousImages", fields: [previousId], references: [id]) previousId Int? @unique next GeneratedImage? @relation("PreviousImages") isFinal Boolean @default(true) version Int @default(1) garments Garment[] // N:M: prendas que aparecen en esta imagen approvedBy User? @relation("Approvals", fields: [approvedById], references: [id]) approvedById Int? approvedAt DateTime? generatedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt pipelineStatus PipelineStatus @default(PENDING) pipelineInformation Json? revisionInformation Json? revisionStatus RevisionStatus @default(PENDING) pose Pose? } enum ImageStatus { BYPASS PENDING INCOMPLETE UNPUBLISHED PENDING_APPROVAL APPROVED REJECTED PENDING_REGENERATION CANCELLED } enum RevisionStatus { PENDING GENERATING PENDING_APPROVAL EDITING FIXING PRE_APPROVED APPROVED ERROR } enum PipelineStatus { PENDING QUEUED PROCESSING FINISHED COMPLETED ERROR }

Campos Clave

  • name: Nombre del archivo o imagen
  • url: URL de la imagen generada en GCS (opcional — puede estar vacía mientras el pipeline no terminó)
  • status: Estado en el flujo de aprobación del cliente
  • reason: Razón de rechazo (si estado es REJECTED)
  • isFinal: Indica si es la versión final
  • version: Número de versión (para versionado)
  • previousId: Referencia a imagen anterior (cadena de versiones)
  • approvedById / approvedAt: Usuario y timestamp de aprobación
  • generatedAt: Timestamp de cuando el pipeline generó la imagen
  • pipelineStatus: Estado interno del pipeline de generación
  • pipelineInformation: Metadata JSON del pipeline (IDs externos, logs, etc.)
  • revisionStatus: Estado del flujo de revisión interno (equipo Rial)
  • revisionInformation: Metadata JSON del proceso de revisión
  • pose: Pose de la imagen generada (enum Pose)

Sistema de Versionado y Rechazo

Las imágenes pueden tener múltiples versiones encadenadas via previousId → next. Cuando se solicita una mejora o corrección:

  1. Se crea una nueva GeneratedImage con version = anterior + 1
  2. Se establece previousId apuntando a la versión anterior
  3. La imagen anterior pasa a tener isFinal = false; la nueva queda con isFinal = true
Flujo de rechazo

Cuando una imagen es rechazada por el cliente:

  1. La imagen rechazada queda con status = REJECTED y reason con el motivo
  2. Se crea una nueva GeneratedImage con:
    • status = PENDING_REGENERATION — indica que está en cola para ser regenerada
    • version = anterior + 1
    • previousId apuntando a la imagen rechazada

El estado PENDING_REGENERATION actúa como marcador de que existe una nueva versión pendiente de generar como consecuencia de un rechazo.

Relaciones

  • project: Proyecto al que pertenece
  • upload: SKU al cual se relaciona (ProjectImage)
  • previous / next: Cadena de versiones
  • garments[]: Prendas que aparecen en esta imagen (N:M)
  • approvedBy: Usuario que aprobó la imagen

👤 Modelos

Model (Modelo)

Representa los modelos del catálogo Rial. Pertenecen a una compañía y se asocian a marcas mediante relación N:M (un modelo puede usarse en varias marcas).

model Model { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt name String gender Gender age Int image String companyId Int? company Company? @relation(fields: [companyId], references: [id]) brands Brand[] // N:M con Brand projects Project[] // N:M con Project baseImages ModelImage[] status ModelStatus @default(ACTIVE) } model ModelImage { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt url String pose Pose? isPreview Boolean @default(false) modelId Int model Model @relation(fields: [modelId], references: [id]) } enum ModelStatus { ACTIVE DEPRECATED } enum Gender { MALE FEMALE OTHER }

Campos Clave

  • name: Nombre del modelo
  • gender: Género del modelo
  • age: Edad aproximada del modelo
  • image: URL de la imagen de referencia del modelo
  • companyId: Referencia a la compañía (opcional; si es null, el modelo puede ser público)
  • status: Estado del modelo — ACTIVE disponible para uso, DEPRECATED retirado

ModelImage — Imágenes base del modelo

Cada modelo puede tener múltiples imágenes base, una por pose.

CampoTipoDescripción
urlStringURL de la imagen en GCS
posePose?Pose que representa esta imagen
isPreviewBooleanSi es la imagen de vista previa del modelo

Tipos de Modelos

  • Los modelos se asocian a marcas mediante la relación N:M (brands[]). Una compañía tiene sus modelos y cada modelo puede estar en una o más marcas.

Relaciones

  • company: Compañía a la que pertenece el modelo (opcional)
  • brands[]: Marcas en las que está disponible este modelo (N:M)
  • projects[]: Proyectos donde se usa este modelo (N:M)
  • baseImages[]: Imágenes base del modelo por pose

🔔 Notificaciones

Notification (Notificación)

Registra notificaciones enviadas a usuarios (email, WhatsApp, etc.), asociadas a una carpeta de proyectos y generadas a partir de una plantilla.

model Notification { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) title String description String link String folderId Int? folder ProjectFolder? @relation(fields: [folderId], references: [id]) isRead Boolean @default(false) templateId Int template NotificationTemplate @relation(fields: [templateId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }

Campos Clave

  • title: Título de la notificación
  • description: Cuerpo o descripción del mensaje
  • link: Enlace asociado de rial-ai.com
  • folderId: Al caso que se relaciona la notificación (si es que aplica)
  • isRead: Si el usuario ya leyó la notificación
  • templateId: Plantilla con la que se generó el mensaje

Relaciones

  • folder: Carpeta de proyectos asociada (opcional)
  • template: Plantilla de notificación usada

NotificationTemplate (Plantilla de Notificación)

Define plantillas reutilizables para notificaciones (email, WhatsApp). El publicId identifica el tipo de evento (enum).

model NotificationTemplate { id Int @id @default(autoincrement()) publicId NotificationTemplateType @unique title String body String variables String[] twilioTemplateSid String role UserRole createdAt DateTime @default(now()) updatedAt DateTime @updatedAt notifications Notification[] } enum NotificationTemplateType { ADMIN_PROJECT_CREATED // Notificación para administrador cuando se crea un proyecto/caso nuevo ADMIN_NEW_REJECTIONS // Notificación para administrador cuando se rechazan imágenes COMPANY_PROJECT_CREATED // Notificación para cliente cuando se termina de crear un proyecto nuevo COMPANY_PROJECT_PENDING_APPROVAL // Notificación para cliente cuando se generan nuevas imágenes COMPANY_PROJECT_READY_FOR_DOWNLOAD // Notificación para cliente cuando se completa/aprueba un caso/proyecto }

Campos Clave

  • publicId: Tipo de notificación (enum); identifica el evento que dispara esta plantilla
  • title / body: Texto de la plantilla
  • variables: Lista de nombres de variables que se reemplazan al enviar (ej. nombre de carpeta, link)
  • twilioTemplateSid: ID de la plantilla en Twilio para mensajes WhatsApp
  • role: Rol del usuario al que va dirigida (ADMIN, COMPANY_ADMIN, BRAND_ADMIN)

Relaciones

  • notifications[]: Notificaciones generadas con esta plantilla

💬 Sistema de Chat

Chat

Hilo de conversación asociado a un proyecto o a un SKU específico para que exista una revisión cruzada dentro del mismo equipo de RIAL. Los chats sin resolver bloquean la publicación de una carpeta de proyectos.

model Chat { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt isResolved Boolean @default(false) resolvedAt DateTime? projectId Int projectImageId Int? project Project @relation(fields: [projectId], references: [id]) projectImage ProjectImage? @relation(fields: [projectImageId], references: [id]) messages ChatMessage[] }

Campos Clave

  • isResolved: Indica si el hilo fue resuelto — los chats sin resolver bloquean la publicación
  • resolvedAt: Timestamp de cuándo se marcó como resuelto
  • projectId: Proyecto al que pertenece el chat
  • projectImageId: SKU específico al que aplica el comentario (opcional — puede ser a nivel de proyecto)

Relaciones

  • project: Proyecto asociado al chat
  • projectImage: SKU específico (opcional)
  • messages[]: Mensajes del hilo

ChatMessage (Mensaje de Chat)

Mensaje individual dentro de un hilo de chat.

model ChatMessage { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt content String chatId Int userId Int chat Chat @relation(fields: [chatId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id]) }

Campos Clave

  • content: Texto del mensaje
  • chatId: Hilo al que pertenece el mensaje
  • userId: Usuario que envió el mensaje (puede ser ADMIN o BRAND_ADMIN)

⚙️ Sistema de Jobs

Jobs asíncronos que representan tareas de larga duración ejecutadas por los workers. El frontend hace polling para mostrar el progreso en tiempo real.

Job

model Job { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) status JobStatus @default(PENDING) errorMessage String? userId Int user User @relation("UserJob", fields: [userId], references: [id]) createdAt DateTime @default(now()) startedAt DateTime? finishedAt DateTime? type JobType payload Json // Filtros y parámetros de entrada del job result Json? // Resultado final (ej: signed URLs de descarga) progress Int @default(0) totalBatches Int? currentBatch Int @default(0) batches JobBatch[] } enum JobStatus { PENDING // Creado, esperando worker RUNNING // Worker procesando COMPLETED // Finalizado exitosamente FAILED // Error irrecuperable RETRYING // Reintentando tras fallo parcial CANCELLED // Cancelado manualmente } enum JobType { IMAGE_DOWNLOAD // Descarga de imágenes (ZIP con signed URLs de GCS) REPORT_GENERATION // Generación de reporte Excel de imágenes METRICS_CALCULATION // Cálculo de métricas de admin FACESWAP_RECOGNITION // Reconocimiento facial para proyectos FACESWAP }

Campos Clave

  • status: Estado actual del job (el frontend hace polling hasta COMPLETED o FAILED)
  • type: Qué tipo de tarea realiza
  • payload: Filtros y parámetros de entrada enviados al worker
  • result: Resultado devuelto por el worker (para descargas: array de signedUrls)
  • progress: Porcentaje de avance (0-100)
  • totalBatches / currentBatch: Para jobs procesados en lotes

Relaciones

  • user: Usuario que creó el job
  • batches[]: Lotes de procesamiento del job

JobBatch (Lote de Job)

Divide un job grande en lotes para procesamiento paralelo o incremental.

model JobBatch { id Int @id @default(autoincrement()) jobId Int job Job @relation(fields: [jobId], references: [id], onDelete: Cascade) batchNumber Int status JobBatchStatus @default(PENDING) result Json? errorMessage String? startedAt DateTime? finishedAt DateTime? createdAt DateTime @default(now()) } enum JobBatchStatus { PENDING // Esperando procesamiento RUNNING // Procesando DONE // Completado exitosamente FAILED // Error en este lote }

📰 Gestión de Contenido

Post (Publicación)

Sistema de publicaciones y contenido de prensa para el sitio web y blog.

model Post { id Int @id @default(autoincrement()) publicId String @unique @default(uuid()) title String description String publicationDate DateTime? image String file String tags String[] type PostType isPublished Boolean @default(false) authorName String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } enum PostType { PUBLICATION PRESS }

Campos Clave

  • title: Título de la publicación
  • description: Contenido o descripción del post
  • publicationDate: Fecha de publicación programada
  • image: URL de imagen destacada
  • file: URL del archivo asociado
  • tags: Array de etiquetas para categorización
  • type: Tipo de publicación
    • PUBLICATION: Artículos del blog
    • PRESS: Notas de prensa
  • isPublished: Estado de publicación
  • authorName: Nombre del autor

🔗 Diagrama de Relaciones

El diagrama de relaciones se encuentra en el siguiente enlace: Diagrama de Relaciones .

Diagrama de Relaciones de la Base de Datos
Last updated on